tags:

views:

600

answers:

2

In XSLT, is there a way to determine where you are in an XML document when processing an element?

Example: Given the following XML Doc Fragment...

<Doc>
  <Ele1>
    <Ele11>
      <Ele111>
      </Ele111>
    </Ele11>
  </Ele1>
  <Ele2>
  </Ele2>
</Doc>

In XSLT, if my context is the Element "Ele111", how can I get XSLT to output the full path? I would want it to output: "/Doc/Ele1/Ele11/Ele111".

The context of this question: I have a very large, very deep document that I want to traverse exhaustively (generically using recursion), and if I find an element with a particular attribute, I want to know where I found it. I suppose I could carry along my current path as I traverse, but I would think XSLT/XPath should know.

+2  A: 

Don't think this is built into XPath, you probably need a recursive template, like the one here, which I've based this example on. It will walk every element in an XML document and output the path to that element in a style similar to the one you've described.

<?xml version="1.0" encoding="UTF-8"?>
<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:template match="/">
        <paths>
            <xsl:apply-templates/>
        </paths>
    </xsl:template>

    <xsl:template match="//*">
        <path>
        <xsl:for-each select="ancestor-or-self::*">
            <xsl:call-template name="print-step"/>
        </xsl:for-each>
        </path>
        <xsl:apply-templates select="*"/>
    </xsl:template>

    <xsl:template name="print-step">
        <xsl:text>/</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>[</xsl:text>
        <xsl:value-of select="1+count(preceding-sibling::*)"/>
        <xsl:text>]</xsl:text>
    </xsl:template>

</xsl:stylesheet>

There are a few complications; consider this tree:

<root>
  <child/>
  <child/>
</root>

How do you tell the difference between the two child nodes? So you need some index into your item-sequence, child[1] and child[2], for example.

Brabster
+1  A: 

You can use the ancestor XPath Axes to walk all parent, and grandparents.

<xsl:for-each select="ancestor::*">...
Mister Lucky