Search code examples
xmlxsltxpathparent

Find position of parent node using xpath


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.

  1. <xsl:number format="1" select="catalog/cd/preceding-sibling::..[position()]" />
  2. <xsl:number format="1" select="./parent::..[position()]" /><br/>
  3. <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.


Solution

  • 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.