我有一个关于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元素?提前致谢
- 阿里
答案 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?在这种情况下,您需要转义所有标记(例如,“<
”为“<
”。查看我网站上的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>