根据我的理解,XSLT Identity转换模板通过迭代XML结构并复制所有子节点和属性来工作。但是当我尝试使用match
<xsl:template>
来覆盖节点以进行一些更改时,我无法理解为什么需要在覆盖模板中添加<xsl:apply-templates/>
,因为理想情况下, identity transform应该处理递归逻辑。
例如:
对于XML结构:
<page site="TestSite" name="Test_QuestionAnswer1">
<testNode1>
<testNode2>
</page>
我有以下XSL转换:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="page">
<refbody>
<xsl:attribute name="id">
<xsl:value-of select="@name"></xsl:value-of>
</xsl:attribute>
<xsl:apply-templates></xsl:apply-templates> <!-- ---why is this line needed? Shouldn't the Identity transform template handle the recursion logic? -->
</refbody>
</xsl:template>
</xsl:stylesheet>
用于产生以下输出:
<?xml version="1.0" encoding="UTF-8"?>
<refbody id="Test_QuestionAnswer1">
<testNode1>
<testNode2>
</refbody>
如果不添加xsl:apply-templates
部分,它只会生成第一个节点,而不会遍历子节点。我一直在阅读Identity变换将整个XML文档映射到类似的XML文档作为输出。为什么在这种情况下它不起作用?
答案 0 :(得分:2)
您要覆盖的身份模板
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
按设计, 显式 使用xsl:apply-templates
继续匹配节点的子节点之间的模式匹配。任何重写模板都必须遵循相同的形式,如果它也希望其子元素进行模板模式匹配。
这比您建议的处理模型更有意义,因为有些情况下您不希望匹配继续是 隐式 匹配递归地应用。一个简单的例子是你想删除一个元素(包括它的后代):
<xsl:template match="ElementToDelete"/>
有机会控制子节点是否被处理是一个优点,因为它提供了通常方便的控制机会。
答案 1 :(得分:1)
使用一组模板实现身份转换。当您添加一个匹配某些具有更高优先级的输入的模板时,它是您的模板,用于确定评估模板时会发生什么。如果你想跳过一些或所有孩子,你的模板可以做到这一点;如果你想在某个遥远的位置处理一个元素,你的模板可以做到这一点。执行身份转换的模板不处理您匹配的元素:您的模板是。他们无法确定模板中发生的情况,包括应评估apply-templates指令的位置和时间。 (如果可以的话,你会如何修改身份转换以使用其所有后代抑制一个元素?或者在frontmatter元素的末尾插入一个目录?)