Reputation: 5735
I have the following XML:
<bookstore>
<author name="King">
<book id="book1"><title>Title1</title></book>
<book id="book2"><title>Title2</title></book>
<book id="book3"><title>Title3</title></book>
<book id="book4"><title>Title4</title></book>
</author>
</bookstore>
then I have an XSLT template, such as:
<xsl:template>
<xsl:param name="booksPath" select="'bookstore/author/book'"/>
<xsl:for-each select="*[local-name() = $booksPath]">
<p><xsl:value-of select="title" /></p>
</xsl:for-each>
</xsl:template>
and this for-each loop does not work. I want to iterate on books What am I doing wrong?
Upvotes: 0
Views: 2463
Reputation: 243479
While full dynamic XPath evaluation isn't part of either XSLT 1.0/XPath 1.0 or XSLT 2.0/XPath 2.0, one can produce an XSLT 1.0 implementation of something that would work in a rather limited way:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="vrtfEvalResult">
<xsl:call-template name="eval">
<xsl:with-param name="pPath" select="'/bookstore/author/book'"/>
</xsl:call-template>
</xsl:variable>
<xsl:for-each select="ext:node-set($vrtfEvalResult)/*">
<p><xsl:value-of select="title" /></p>
</xsl:for-each>
</xsl:template>
<xsl:template match="text()"/>
<xsl:template match="Path" name="eval">
<xsl:param name="pPath" select="."/>
<xsl:param name="pContext" select="/"/>
<xsl:choose>
<!-- If there is something to evaluate -->
<xsl:when test="string-length($pPath) >0">
<xsl:variable name="vPath" select=
"substring($pPath,2)"/>
<xsl:variable name="vNameTest">
<xsl:choose>
<xsl:when test="not(contains($vPath, '/'))">
<xsl:value-of select="$vPath"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select=
"substring-before($vPath, '/')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:call-template name="eval">
<xsl:with-param name="pPath" select=
"substring-after($pPath, $vNameTest)"/>
<xsl:with-param name="pContext" select=
"$pContext/*[name()=$vNameTest]"/>
</xsl:call-template>
</xsl:when>
<!-- Otherwise we have evaluated completely the path -->
<xsl:otherwise>
<xsl:copy-of select="$pContext"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<bookstore>
<author name="King">
<book id="book1">
<title>Title1</title>
</book>
<book id="book2">
<title>Title2</title>
</book>
<book id="book3">
<title>Title3</title>
</book>
<book id="book4">
<title>Title4</title>
</book>
</author>
</bookstore>
the wanted, correct result is produced:
<p>Title1</p>
<p>Title2</p>
<p>Title3</p>
<p>Title4</p>
Upvotes: 1
Reputation: 167571
If you really need or want to use dynamic XPath evaluation from a string then you need an extension function like saxon:evaluate e.g. <xsl:for-each select="saxon:evaluate($booksPath)" xmlns:saxon="http://saxon.sf.net/">...</xsl:for-each>
.
Upvotes: 2