Friday, February 1, 2008

How to Get XPath to an XML Node

There are a lot of XSL templates out there that get a human readable path to a node. But none that cover the case when there are more than one node of the same element at the same level.

In order to solve this problem you can use the following code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes">
    <xsl:template match="@*|node()">
      <xsl:copy>
        <xsl:tagibute name="position">
          <xsl:call-template name="xpath.position">
            <xsl:apply-templates select="@*|node()"></xsl:apply-templates>
          </xsl:call-template>
        </xsl:tagibute>
      </xsl:copy>
    </xsl:template>

    <xsl:template name="xpath.position">
     <xsl:param name="node" select="."></xsl:param>
     <xsl:param name="path" select="''"></xsl:param>
     <xsl:variable name="next.path">
      <xsl:text>*[position()=</xsl:text>
      <xsl:value-of select="$node/count(preceding-sibling::*)+1">
       <xsl:text>]</xsl:text>
       <xsl:if test="$path != ''">/</xsl:if>
       <xsl:value-of select="$path"></xsl:value-of>
      </xsl:value-of>
     </xsl:variable>

   <xsl:choose>
    <xsl:when test="$node/parent::*">
      <xsl:call-template name="xpath.position">
        <xsl:with-param name="node" select="$node/parent::*"></xsl:with-param>
          <xsl:with-param name="path" select="$next.path"></xsl:with-param>
      </xsl:call-template>
    </xsl:when>
 
    <xsl:otherwise>
      <xsl:text>/</xsl:text>
        <xsl:value-of select="$next.path"></xsl:value-of>
      </xsl:otherwise>
    </xsl:choose>
   </xsl:template>
  </xsl:output>
</xsl:stylesheet>

Source: https://www.nilebits.com/blog/2007/03/get-xpath-of-an-xml-node/

No comments:

Post a Comment