好吧,我似乎无法解决这个XSLT 1.0带回家的测验问题。这是源XML ...
<College>
<Class>
<History>
<StudentName>Veronica</StudentName>
</History>
</Class>
<Class>
<History>
<StudentName>Jasmine</StudentName>
</History>
</Class>
<Class>
<History>
<StudentName>Rebecca</StudentName>
</History>
</Class>
</College>
我正在尝试用XSLT 1.0来向第三个“历史”节点添加一个新元素“AddThis”,使用一个参数来表示将“AddThis”添加到下面的“History”节点...
<College>
<Class>
<History>
<StudentName>Veronica</StudentName>
</History>
</Class>
<Class>
<History>
<StudentName>Jasmine</StudentName>
</History>
</Class>
<Class>
<History>
<StudentName>Rebecca</StudentName>
<AddThis>Ok</AddThis>
</History>
</Class>
</College>
非常感谢你花时间阅读这个问题。
编辑:我不得不在“历史”节点内而不是在“历史”节点之外更正新元素“AddThis”的位置,抱歉。
答案 0 :(得分:1)
您的情况永远不会得到满足,因为preceding-sibling::
执行它在锡上所说的内容:它选择前面的兄弟节点。其中History
元素的XML结构中没有任何内容!因此,您的测试属性将始终生成一个等同于test="(0 +1) = 3"
的表达式,即test="false()"
。
您需要重新考虑XPath选择器,即需要选择preceding-sibling::
节点上的parent::
节点; 或您需要重构XSLT,以便模板匹配流自动正确地选择节点。 (类似于match="Class[(position() +1)= $position]"
以选择示例中的第4个位置。)
此外,您的逻辑是奇怪的:XSLT索引/位置是基于1的,而不是像大多数语言一样基于0。因此,通过修改$position
param子句而不是将其添加到谓词的子表达式中来选择第4个元素似乎更清楚。
答案 1 :(得分:1)
此转化:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pNum" select="3"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Class[History]">
<xsl:choose>
<xsl:when test="not(position() = $pNum)">
<xsl:call-template name="identity"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<AddThis>Ok</AddThis>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<College>
<Class>
<History>
<StudentName>Veronica</StudentName>
</History>
</Class>
<Class>
<History>
<StudentName>Jasmine</StudentName>
</History>
</Class>
<Class>
<History>
<StudentName>Rebecca</StudentName>
</History>
</Class>
</College>
生成想要的正确结果:
<College>
<Class>
<History>
<StudentName>Veronica</StudentName>
</History>
</Class>
<Class>
<History>
<StudentName>Jasmine</StudentName>
</History>
</Class>
<Class>
<History>
<StudentName>Rebecca</StudentName>
</History>
<AddThis>Ok</AddThis>
</Class>
</College>
解释:非常典型地覆盖身份规则。
XSLT 2.0解决方案:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pNum" select="3"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Class[History][position() = $pNum]">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<AddThis>Ok</AddThis>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
解释:几乎与XSLT 1.0解决方案相同,但更短,因为在XSLT 2.0中,变量/参数引用以匹配模式发生是合法的 - 因此我们完全摆脱明确的条件。
更新:OP现在已经修改了问题:
“抱歉,”AddThis“元素被假设在里面添加 第三个“历史”节点,不在第三个“历史”节点之外,我的不好。一世 在我的问题帖子中纠正了此我如何编辑你的XSLT 1.0 纠正这个?谢谢。 - Bug Spray “
以下是相应修改的解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pNum" select="3"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Class[History]">
<xsl:choose>
<xsl:when test="not(position() = $pNum)">
<xsl:call-template name="identity"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="." mode="add"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="node()|@*" mode="add" name="id2">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="add"/>
</xsl:copy>
</xsl:template>
<xsl:template match="History/StudentName" mode="add">
<xsl:call-template name="id2"/>
<AddThis>Ok</AddThis>
</xsl:template>
</xsl:stylesheet>