您好,我是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传递,让第二个模板处理节点选择,但仍然是同样的错误。
答案 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>