【问题标题】:XSLT 1.0 - How to define a template match with a test clause to compare it to a parameter valueXSLT 1.0 - 如何使用测试子句定义模板匹配以将其与参数值进行比较
【发布时间】:2011-12-16 05:05:31
【问题描述】:

好吧,我似乎无法解决这个 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”添加到哪个“历史”节点,如下所示...

<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”在“历史”节点内的位置,而不是在“历史”节点之外,抱歉。

【问题讨论】:

  • 好问题,+1。存在一个更简单的解决方案,不需要使用 count()preceding:: 轴。
  • @Dimitre Novatchev,对不起,“AddThis”元素应该被添加到第三个“历史”节点内,而不是第三个“历史”节点之外,我的错。我在我的问题帖子中更正了这一点。我将如何编辑您的 XSLT 1.0 来纠正这个问题?谢谢。
  • @_Bug Spray:我已经更新(查看最后)我的答案,以便该解决方案现在可以产生您想要的最新输出。以后,请提出新问题,不要更改相同的问题。
  • @Dimitre Novatchev,非常感谢你,从现在开始,我将提出一个新问题,而不是更改同一个问题。

标签: xslt


【解决方案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 编辑为 纠正这个?谢谢。 – 杀虫剂"

下面是相应修改的解决方案

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

【讨论】:

    【解决方案2】:

    你的条件永远不会满足,因为preceding-sibling:: 做了它在锡上所说的:它选择前面的 sibling 节点。您的 XML 结构中不会有任何 History 元素!所以你的测试属性总是会产生一个等价于:test="(0 +1) = 3"的表达式,即test="false()"

    您将需要重新考虑您的 XPath 选择器,即您需要在 parent:: 节点上选择 preceding-sibling:: 节点; 或者您需要重构您的 XSLT,以便模板匹配流程自动正确选择节点。 (类似于match="Class[(position() +1)= $position]" 在您的示例中选择第四个位置。)

    此外,您的逻辑很奇怪:XSLT 索引/位置是从 1 开始的,而不是像大多数语言那样从 0 开始。因此,通过修改 $position 参数子句来选择第 4 个元素似乎更清晰,而不是通过将其添加到谓词的子表达式中。

    【讨论】:

    • 感谢您指出我的错误。我更正了我的 XSLT 1.0,它现在适用于这些更改,我将原始测试子句更改为
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-29
    • 1970-01-01
    • 2015-05-05
    相关资源
    最近更新 更多