How to get the position of parent node in the complete document using xpath?
say I have the following xml:
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
<cd>
<title>Hide your heart</title>
<artist>Bonnie Tyler</artist>
<country>UK</country>
<company>CBS Records</company>
<price>9.90</price>
<year>1988</year>
</cd>
</catalog>
and I have a XSLT to convert it into HTML, which is as follows (only snippet):
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="cd">
<p>
<xsl:number format="1. "/><br/>
<xsl:apply-templates select="title"/>
<xsl:apply-templates select="artist"/>
</p>
</xsl:template>
<xsl:template match="title">
<xsl:number format="1" select="????" /><br/>
Title: <span style="color:#ff0000">
<xsl:value-of select="."/></span>
<br />
</xsl:template>
What should I write at the place of ???? to get position of the parent cd tag in the document. I have tried many expressions but nothing seems to be working. May be I am doing it altogether wrong.
<xsl:number format="1" select="catalog/cd/preceding-sibling::..[position()]" />
<xsl:number format="1" select="./parent::..[position()]" /><br/>
<xsl:value-of select="count(cd/preceding-sibling::*)+1" /><br/>
I am interpreting 2nd as select current node's parent axis and then tell the position of parent of the current node. Why is it not working? What is the correct way to do this.
FYI: I expect the code to print the position of parent cd tag of the current title tag uder processing.
Please can someone tell me how to do this.
count(../preceding-sibling::cd) + 1
You can run it here (note I removed the other number you were outputting, just for clarity).
You were on the right lines, but remember that predicates are used only to filter nodes, not to return information. So:
../*[position()]
...effectively says "find me the parent that has a position". It returns the node, not the position itself. The predicate is just a filter.
In any case there are pitfalls with using position()
, and it can be used to return the position of the current, context node only - not another node.
Utkanos's answer works fine but my experience is that, when the xml document is large, this could lead to performance issues.
In this scenario you could simply pass the position of the parent in a param.
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="cd">
<p>
<xsl:number format="1. "/><br/>
<xsl:apply-templates select="title">
<xsl:with-param name="parent_position" select="position()"/> <!-- Send here -->
</xsl:apply-templates>
<xsl:apply-templates select="artist"/>
</p>
</xsl:template>
<xsl:template match="title">
<xsl:param name="parent_position"/> <!-- Receive here -->
<xsl:number format="1" select="$parent_position"/><br/>
Title: <span style="color:#ff0000">
<xsl:value-of select="."/></span>
<br />
</xsl:template>
result:
<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><body>
<p>1. <br>1<br>
Title: <span style="color:#ff0000">Empire Burlesque</span><br>Bob Dylan</p>
<p>2. <br>1<br>
Title: <span style="color:#ff0000">Hide your heart</span><br>Bonnie Tyler</p>
</body></html>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With