1

我有一个关于 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>

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

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

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

——阿里

4

2 回答 2

5

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

在您的情况下,模板优先级甚至不是问题。您有两种不同的模板规则,一种是匹配<medication>元素,一种是匹配<name>元素。这些永远不会发生冲突,所以这不是模板优先级或覆盖的问题。问题是您的代码实际上从未将模板应用于<name>元素。当您说<xsl:copy-of select="."/>on 时<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)。

关于模板优先级如何工作的完整而简明的描述可以在我的网站上的“XSLT 工作原理”中找到。

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

于 2009-05-18T18:56:42.637 回答
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>
于 2009-05-18T13:51:17.540 回答