XSLT 1.0 - 如何使用test子句定义模板匹配,以将其与参数值进行比较

时间:2011-10-27 03:00:33

标签: xslt

好吧,我似乎无法解决这个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”的位置,抱歉。

2 个答案:

答案 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>