5

是否可以匹配“尚未匹配/处理的任何节点”?最好不要让我的样式表变成一个巨大的 for-each/Choose 语句,因为当前的顺序很关键。

该项目仍在开发中,并且已经在实时环境中使用,所以简单地说,代码处于快速变化的状态,以响应我们输入的实时数据。我正在通过 FO 从 XML 生成 PDF 文档其中可能有我还不知道的节点,并且想在我的 XSL-FO 转换中添加“故障转移”指令,将文档开头的所有下落不明的节点以鲜红色显示,以加快发现速度。

我不能只忽略惊喜节点,因为需要处理数据。我越快找到“孤儿”数据,我就能越快得到妥善处理并将其排除在外。

我尝试过使用<xsl:template match="*">...</xsl:template>各种 priority="" 设置,但它当然适用于每个节点。

例如,我可能在一个部分中有这个,因为这些 XML 块不能保证以正确的输出顺序出现。(代码块格式对我不起作用 - 四个空格缩进没有任何结果,抱歉 :(

<xsl:template match="AccountSummary">
    <fo:block margin-left="2" space-before="1" space-after="1" text-align="center">
        <xsl:apply-templates select="Label"/>
    </fo:block>
    <xsl:apply-templates select="AccountInfo"/>
    <xsl:apply-templates select="AccountProfile"/>
    <xsl:apply-templates select="ChangeInValueOfAccounts"/>
    <!-- ... more goes here -->
</xsl:template>

我想做类似的事情

<xsl:template match="AccountSummary">
    <fo:block margin-left="2" space-before="1" space-after="1" text-align="center">
        <xsl:apply-templates select="Label"/>
    </fo:block>
    <xsl:apply-templates select="AccountInfo"/>
    <xsl:apply-templates select="AccountProfile"/>
    <xsl:apply-templates select="ChangeInValueOfAccounts"/>
    <!-- ... more goes here -->
    <xsl:for-each select="not otherwise matched">
        <!-- call zomgRED template -->
    </xsl:for-each>
</xsl:template>

理想情况下,我宁愿zomgREDs 在顶部,但在底部也可以。或用文本标记标记。任何可以在最终文档中吐出文本而不是默默吃掉它的东西。

4

3 回答 3

2

以下是您如何能够获得一些您正在寻找的东西的味道。虽然没有将未处理的节点推到顶部:

1)在您的样式表中进行身份转换:

<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>

2)确保您<xsl:apply-templates select="*"/>从所有其他更具体的模板中调用以让解析器运行

这个想法是您的特定模板处理预期的 XSL-FO 转换,而身份转换只是将所有其他内容转储到结果树中。递归调用将确保您真正接触到所有节点(这是让它们“记录在案”的唯一方法),并且身份转换将与您没有捕获的那些相匹配。

#2 建议实际上可能会妨碍您的 XSL-FO 逻辑,因此可能并不真正可行,如果没有示例输入和您当前的 XSL-FO 转换,我无法判断。也许将其添加到问题中?

于 2012-05-04T19:01:04.830 回答
0

注意:根据更新的问题完全替换了原始答案。

你可以这样做,但你需要列出那些你不想再次获得 zomgRed 模板的项目:

<xsl:template match="AccountSummary"> 
    <fo:block margin-left="2" space-before="1" space-after="1" text-align="center"> 
        <xsl:apply-templates select="Label"/> 
  </fo:block> 
  <xsl:apply-templates select="AccountInfo"/> 
  <xsl:apply-templates select="AccountProfile"/> 
  <xsl:apply-templates select="ChangeInValueOfAccounts"/> 
  <-- ... more goes here --> 
    <xsl:apply-templates mode='fallback' select * />

</xsl:template>

<xsl:template match='AccountInfo|AccountProfile|ChangeInValueOfAccounts| ... more goes here' mode='fallback' />

<xsl:template match='*' mode='fallback'>
   <!-- call zomgRED template --> 
</xsl:template>

我已经for-each用另一个替换了你的apply-templates,但现在我们正在使用一种模式。只有相同模式的模板才会匹配。匹配“*”的模板仅在该模式下匹配,因此在其他情况下不会被调用。单行模板以相同的模式匹配,并且匹配你已经处理过的所有节点,并且什么都不做。由于它比“*”更具体,它将运行(并且什么也不做)而不是那些节点的“*”模板。

作为具有重复节点列表的单行模板的替代方案,您可以将相同的模式添加到所有现有模板(AccountInfo、AccountProfile 等)以及每个模板的 apply-templates 语句。这是一个风格问题,你会发现它更易于维护。

于 2012-05-04T19:16:57.177 回答
0

这是一个如何做到这一点的示例(仅跟踪不匹配的节点——如果需要,可以以相同的方式实现不匹配的属性跟踪):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <!-- Catch all node - types template -- must be the top-most -->
 <xsl:template match="node()">
  Warning: this node is unmatched by any templates:

  "<xsl:copy-of select="."/>"
 </xsl:template>

 <xsl:template match="nums">
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="num[following-sibling::num[1] -1 = .]">
  <xsl:copy-of select="."/>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于以下 XML 文档时:(特意选择很简单,以说明这个简单的解决方案)

<nums>
  <num>01</num>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <num>05</num>
  <num>06</num>
  <num>07</num>
  <num>08</num>
  <num>09</num>
  <num>10</num>
</nums>

生成结果,包括一个不匹配元素的警告:

<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
  Warning: this node is unmatched by any templates:

  "<num>10</num>"

请注意:如果样式表导入/包含其他样式表,此解决方案将不起作用。在这种情况下,必须将包罗万象的模板放在最先出现(或具有最低导入优先级)的样式表中。

于 2012-05-05T03:01:17.440 回答