XSLT模板覆盖

时间:2009-05-18 13:42:22

标签: xslt templates override

我有一个关于XSLT模板覆盖的小问题。 对于我的XML段:

<record>
  <medication>
    <medicine>
      <name>penicillin G</name>
      <strength>500 mg</strength>
    </medicine>
  </medication>
</record>

在我的XSLT表中,我按以下顺序有两个模板:

 <xsl:template match="medication">
   <xsl:copy-of select="." />
   </xsl:template>
   <xsl:template match="medicine/name">
   <text>!unauthorized information!</text>
 </xsl:template>

我想要做的是将药物元素下的所有内容复制到“name”元素(或我明确定义的任何其他元素)以外的输出。最终的xml将以RAW XML格式显示给用户。换句话说,我想要的结果是:

<record>
  <medication>
    <medicine>
      <text>! unauthorized information!</text>
      <strength>500 mg</strength>
    </medicine>
  </medication>
</record>

然而,我得到与输入相同的XML,即没有用文本替换元素。第二个模板匹配的任何想法都没有覆盖第一个模板中的name元素?提前致谢

- 阿里

2 个答案:

答案 0 :(得分:5)

模板顺序无关紧要。它可能被考虑的唯一情况(这是依赖于处理器的)是当你有一个不可解决的冲突,即错误条件。在这种情况下,XSLT处理器通过选择最后一个错误来从错误中恢复是合法的。但是,您永远不应该编写依赖于此行为的代码。

在您的情况下,模板优先级甚至不是问题。您有两个不同的模板规则,一个匹配<medication>元素和一个匹配的<name>元素。这些永远不会发生冲突,所以这不是模板优先级或覆盖的问题。问题是您的代码实际上从未将模板应用于<name>元素。当您在<xsl:copy-of select="."/>上说<medication>时,您会说:“执行<medication>的深层复制。任何模板规则将为后代节点触发的唯一方法是,如果您明确应用模板(使用<xsl:apply-templates/>

我给你的解决方案基本上与alamar相同,只是它使用单独的处理“模式”,它将规则与样式表中的所有其他规则隔离开来。通用match="@* | node()"模板使模板规则以递归方式应用于子(和属性),这使您有机会覆盖某些节点的行为。

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <!-- ...placeholder for the rest of your code... -->
  <xsl:template match="/record">
    <record>
      <xsl:apply-templates/>
    </record>
  </xsl:template>
  <!-- end of placeholder -->

  <xsl:template match="medication">
    <!-- Instead of copy-of, whose behavior is to always perform
         a deep copy and cannot be customized, define your own
         processing mode. Rules with this mode name are isolated
         from the rest of your code. -->
    <xsl:apply-templates mode="copy-medication" select="."/>
  </xsl:template>

          <!-- By default, copy all nodes and their descendants -->
          <xsl:template mode="copy-medication" match="@* | node()">
            <xsl:copy>
              <xsl:apply-templates mode="copy-medication" select="@* | node()"/>
            </xsl:copy>
          </xsl:template>

          <!-- But replace <name> -->
          <xsl:template mode="copy-medication" match="medicine/name">
            <text>!unauthorized information!</text>
          </xsl:template>

</xsl:stylesheet>

medicine/name”的规则会覆盖“@* | node()”的规则,因为模式的格式(包含“/”)会使其默认优先级(0.5)高于默认优先级“node()”( - 1.0)。

有关模板优先级如何工作的完整而简明的说明,请参阅我网站上的"How XSLT Works"

最后,我注意到您提到要向用户显示“RAW XML”。这是否意味着您希望在浏览器中显示带有所有开始和结束标记的XML?在这种情况下,您需要转义所有标记(例如,“&lt;”为“<”。查看我网站上的XML-to-string utility。如果您需要一个如何使用它的示例,请告诉我。

答案 1 :(得分:2)

添加

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

<xsl:template match="medicine/name">

完全删除<xsl:template match="medication">

<?xml version="1.0" encoding="windows-1251"?>
<xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">

 <xsl:template match="medicine/name">
   <text>!unauthorized information!</text>
 </xsl:template>

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

</xsl:stylesheet>