Reputation: 4749
I'm using the generate-id()
function inside a predicate to compare with a previously generated id. But this does not work and I can't figure out why.
I've created a sample XSLT with input and expected output. Yes I know - this code does seems weird and does not make sense, it is just to find out, why the generate-id()
does not work here.
The problem line is the following:
<xsl:value-of select="a[generate-id(current())=$a_id]/text()"/>
This does not work. Here the complete XML input, XSLT and expected output.
XML Input:
<root>
<test>
<a>1</a>
<a>2</a>
<a>3</a>
</test>
</root>
Expected Output:
<root>
<test>
<a>1</a>
</test>
<test>
<a>2</a>
</test>
<test>
<a>3</a>
</test>
</root>
Result Output (the values are not found with the id search):
<root>
<test>
<a/>
</test>
<test>
<a/>
</test>
<test>
<a/>
</test>
</root>
Here is the XSLT. The problem is in the last template:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
<xsl:output indent="yes"></xsl:output>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="test"/>
</xsl:copy>
</xsl:template>
<xsl:template match="test">
<xsl:for-each select="a">
<xsl:apply-templates select=".." mode="output">
<xsl:with-param name="a_id" select="generate-id()"/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="test" mode="output">
<xsl:param name="a_id"/>
<xsl:copy>
<xsl:element name="a">
<!-- Here the passed a_id cannot be found -->
<xsl:value-of select="a[generate-id(current())=$a_id]/text()"/>
</xsl:element>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Views: 716
Reputation: 167726
Inside of your template match="test"
, the current()
function selects that matched test
so I think you simply want
a[generate-id(.)=$a_id]
to make sure you compare the id of the a
elements and not of the test
with the a
element. Note also that in XSLT 2.0 there is an is
operator so you don't need to pass around ids and compare them, you could pass around the element directly and output it, or, if you need to compare some nodes based on identity, use that is
operator.
Upvotes: 1
Reputation: 70648
The answer to your question is that you need to do this...
<xsl:value-of select="a[generate-id(.)=$a_id]/text()"/>
Or even this...
<xsl:value-of select="a[generate-id()=$a_id]/text()"/>
current()
refers the the current node being matched, which is the test
node. .
refers the the current context (the a
node). See Current node vs. Context node in XSLT/XPath? for more details.
Another answer would be that you may have over-complicated things. You could re-write your XSLT as this instead..
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
<xsl:output indent="yes"></xsl:output>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="test"/>
</xsl:copy>
</xsl:template>
<xsl:template match="test">
<xsl:for-each select="a">
<test>
<xsl:apply-templates select="." />
</test>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1