Is there an XPATH function or operator to compare the depth of nodes?

Viewed 43

Example:

<ul>
    <li>item 1</li>
    <ul>
        <li>item 2</li>
        <li>item 3</li>
        <ul>
            <li>item 5</li> <!-- context node -->
        </ul>
    </ul>
    <li>item 6</li>
</ul>

If the li element with the text item 5 is the context node, the expression following::* would yield the li element with text item 6. Is there a built-in way to get the difference in depth of these nodes? i.e if we defined the root ul as having depth 0, then it's children (li item 1, ul, li item 6) would have depth 1, and so on. li item 5 has depth 3.

The ancestor axis could be used from both nodes, but wonder if there is another way. Another possibility might be to keep state information when traversing the tree and if the parent had following siblings?

1 Answers

The question is tagged as XSLT 2 but as you mentioned tree traversal to keep state information it might be worth mentioning an XSLT 3 accumulator e.g.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">
    
  <xsl:mode use-accumulators="depth"/>
    
  <xsl:accumulator name="depth" as="xs:integer" initial-value="0">
      <xsl:accumulator-rule match="/" select="0"/>
      <xsl:accumulator-rule match="*" select="$value + 1"/>
      <xsl:accumulator-rule match="*" phase="end" select="$value - 1"/>
  </xsl:accumulator>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="*">
      <xsl:comment select="accumulator-before('depth'), count(ancestor-or-self::*)"/>
      <xsl:next-match/>
  </xsl:template>
  
</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/ei5R4uS

I know you have defined the value for the root element as 0 but using 0 for the root node / and then +1 as the depth for its child elements seems more reasonable to me.

Related