使用xsl:for-each中的current()来检索超出for-each范围的节点

时间:2011-06-27 15:48:54

标签: xslt xpath foreach

您好,我是XSLT2.0的初学者,但由于最近的项目需要XML配置,我会试一试。 XML结构如下所示:

<bookstore>
<books>
    <book author="a" title="a1"/>
    <book author="b" title="b1"/>
    <book author="c" title="c1"/>
    <book author="d" title="d1"/>
</books>
<topAuthorList>
    <thisMonth>c,a,d,b</thisMonth>
</topAuthorList>

XSLT看起来像这样:

    <xsl:template match="/bookstore">
    <result>
        <xsl:variable name="varList">
            <xsl:value-of select="topAuthorList/thisMonth"></xsl:value-of>
        </xsl:variable> 

        <test>
            <xsl:value-of select="books/book[@author='a']/@title"></xsl:value-of>
        </test>

        <books>
            <xsl:for-each select="tokenize($varList, ',')">
                <xsl:value-of select="books/book[@author=current()]/@title"></xsl:value-of>
            </xsl:for-each>
        </books>
    </result>
</xsl:template>

但是在XMLSpy(版本2011 rev3)中,它给出了错误信息:

XSLT 2.0 Debugging Error: Error in XPath 2.0 expression (Type error XPTY0004: Expected a node - current item is 'c' of type xs:string)

我有多次搜索谷歌和本网站,但找不到答案。我甚至尝试使用call-template,即将current()作为param传递,让第二个模板处理节点选择,但仍然是同样的错误。

3 个答案:

答案 0 :(得分:2)

这有效:

  <xsl:template match="/bookstore">
    <result>
      <xsl:variable name="varList">
        <xsl:value-of select="topAuthorList/thisMonth"></xsl:value-of>
      </xsl:variable> 

      <test>
        <xsl:value-of select="books/book[@author='a']/@title"></xsl:value-of>
      </test>

      <books>
        <xsl:variable name="books" select="/bookstore/books"/>
        <xsl:for-each select="tokenize($varList, ',')">
          <xsl:value-of select="$books/book[@author=current()]/@title"></xsl:value-of>
        </xsl:for-each>
      </books>
    </result>
  </xsl:template>

我所做的只是将/bookstore/books放在变量中,然后从变量中进行查找。我有一个直观的理解为什么需要它,但没有一些研究没有确切的正式理由。也许这里的其他XML专家可以参与其中。

编辑:我在Michael Kay的优秀“XSLT 2.0和XPath 2.0”巨着中找到了相关信息,第625页:

  

有根路径表示路径   从树的根节点开始   包含上下文节点

由于您的案例中的上下文节点是裸字符串,因此它不包含您要查找的节点。使用该变量为XPath表达式提供了适当的上下文。

答案 1 :(得分:1)

当您编写<xsl:value-of select="books/book[@author=current()]/@title">时,“books”是“child :: books”的缩写,即book元素,它们是上下文项的子元素。但是什么是上下文项?包含xsl:for-each将上下文项设置为在其select表达式中选择的每个项。但这是对tokenize的调用,因此上下文项是一个字符串,字符串没有子项。

当您深入到层次结构中时,上下文项的概念很有用。当你进行连接时它没用。对于连接,您需要变量。有时你可以使用“。”作为变量之一和“current()”作为另一个变量,但是当它用完蒸汽时你需要真正的命名变量。

顺便说一句,请不要将xsl:value-of用作xsl:variable的子项,除非您确实要创建新的文档树。您几乎可以肯定地将varlist的声明重写为<xsl:variable name="varList" select="topAuthorList/thisMonth">,这不仅可以编写更少的代码,而且效率也更高,因为它避免了构造新树的需要。

答案 2 :(得分:0)

我想你想要:

        <books>
            <xsl:variable name="tokens" select="tokenize($varList, ',')"/>
            <xsl:value-of select="
                for $a in $tokens 
                return books/book[@author=$a]/@title"/>
        </books>