Reputation: 713
I'm running into an odd issue that has me tearing my hair out. I'm attempting to match an XPath in my stylesheet. It works when I hardcode the matching value, but not when I try to get it from a variable. What am I doing wrong here?
XML input (obviously very simplified):
<container>
<items>
<item>
<LocationID>LOCATION_4</LocationID>
</item>
<item>
<LocationID>LOCATION_4</LocationID>
</item>
</items>
</container>
XSLT Template ($DistinctLocations and $dataNode are previously declared variables, my first couple of printouts are to verify they are both in scope)
<xsl:template name="LocationTemplate">
<xsl:for-each select="$DistinctLocations/Location">
<MY-CURRITEM>
<val>
<xsl:copy-of select="." />
</val>
<distinct>
<xsl:copy-of select="$DistinctLocations" />
</distinct>
<node>
<xsl:copy-of select="$dataNode" />
</node>
<itemloc>
<xsl:copy-of select="$dataNode//item[LocationID = 'LOCATION_4'][1]/LocationID" />
</itemloc>
<itemlocdot>
<xsl:copy-of select="$dctNode//risk[LocationID = .][1]/LocationID" />
</itemlocdot>
<itemloctext>
<xsl:copy-of select="$dctNode//risk[LocationID = text()][1]/LocationID" />
</itemloctext>
<itemloc2>
<xsl:copy-of select="$dataNode//item[string(LocationID) = string(.) ][1]/LocationID" />
</itemloc2>
<itemloc3>
<xsl:copy-of select="$dataNode//item[string(LocationID) = string(text()) ][1]/LocationID" />
</itemloc3>
</MY-CURRITEM>
</xsl:for-each>
</xsl:template>
The output:
<MY-CURRITEM>
<val>
<Location>LOCATION_4</Location>
</val>
<distinct>
<DistinctLocations>
<Location>LOCATION_4</Location>
</DistinctLocations>
</distinct>
<node>
<container>
<items>
<item>
<LocationID>LOCATION_4</LocationID>
</item>
<item>
<LocationID>LOCATION_4</LocationID>
</item>
</items>
</container>
</node>
<itemloc>
<LocationID>LOCATION_4</LocationID>
</itemloc>
<itemlocdot />
<itemloctext />
<itemloc2 />
<itemloc3 />
</MY-CURRITEM>
As you can see, the node where I hard-coded the value returns a match. All of the others, where I attempt to match the value from a variable, fail to match. Since the hard-code works, I'm guessing it's some kind of mismatch between types, but I've tried all of combinations of type-casting I can think of and I'm not getting any results.
EDIT: People are requesting the whole stylesheet. It's huge and will take some time to simplify. In the mean time, here's where thevariables came from:
$DistinctLocations is a param passed in from C#
args.AddParam("DistinctLocations", string.Empty, xDistinctLocs.CreateNavigator().Select("/"));
and
<xsl:param name="DistinctLocations" />
$dataNode is the original XML that is being transformed, stored in a variable:
<xsl:variable name="dataNode" select="." />
Upvotes: 1
Views: 1275
Reputation: 117140
Please observe the folowing simplified example:
XML
<root>
<locations>
<location>LOCATION_2</location>
</locations>
<items>
<item>
<id>1</id>
<location>LOCATION_1</location>
</item>
<item>
<id>2</id>
<location>LOCATION_2</location>
</item>
</items>
</root>
XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:for-each select="locations/location">
<location>
<value>
<xsl:value-of select="." />
</value>
<hard-code>
<xsl:copy-of select="//item[location='LOCATION_2']" />
</hard-code>
<dot>
<xsl:copy-of select="//items/item[location=.]" />
</dot>
<current>
<xsl:copy-of select="//items/item[location=current()]" />
</current>
</location>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="utf-8"?>
<root>
<location>
<value>LOCATION_2</value>
<hard-code>
<item>
<id>2</id>
<location>LOCATION_2</location>
</item>
</hard-code>
<dot/>
<current>
<item>
<id>2</id>
<location>LOCATION_2</location>
</item>
</current>
</location>
</root>
Why is the <dot>
element of the result empty? Because in the expression:
"//items/item[location=.]"
the inner dot represents the outeritem
node - not the current location
node. The expression is looking for an item
whose value is equal to the value of its location
child. Of course, no such item exists.
This is why XSLT added the current() function, which does not change context when used in a predicate.
Upvotes: 1