XSLT标识转换逻辑

时间:2017-11-08 21:30:04

标签: xml xslt

根据我的理解,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文档作为输出。为什么在这种情况下它不起作用?

2 个答案:

答案 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元素的末尾插入一个目录?)