0

Using XSLT, I need to locate the tag element from an XML file to start doing the wanted transformations. The tag element is typically the root element.

<tag>
   ...
</tag>

However, a new collection of XML files arrived and some of them have the tag element somewhere else. (its location vary from file to file)

<a>
  <b>
    <tag>
      ...
    </tag>
  </b>
</a>

I would like to know if its possible to obtain the full path/name of tag and store it into a variable, so I could use $tagPath instead of /a/b/tag. I tried using the name() function but it only returns the element name (tag).

Thanks!

  • would xpath-selector '//tag' help? It matches tag elements at arbitrary levels in the file, and knowing the exact path would become obsolete, right? – Stephan Lechner Dec 15 '16 at 23:29
  • Will there only be one occurrence of `tag` in the entire document? If yes, you could use `//tag` to select it - without knowing (or needing to know) the full path, – michael.hor257k Dec 15 '16 at 23:33
  • @michael.hor257k There might have more than one. In those cases, there will have a top-level one (the one described) and some others deeper in the tree. – user3882500 Dec 15 '16 at 23:37
  • Well, then `//tag[1]` should work for selecting the top one. Mind you, it's not a very efficient method, but if you don't know the explicit path... – michael.hor257k Dec 15 '16 at 23:43
  • 1
    Do you mean `(//tag)[1]` @michael.hor257k? – Daniel Haley Dec 15 '16 at 23:48
  • 2
    @DanielHaley Actually, I meant `/descendant::tag[1]` - but oops anyway and thanks for the catch. – michael.hor257k Dec 16 '16 at 00:07

1 Answers1

1

Per the comments above, to find the tag element regardless of position, you can just use \\tag.

If you need the full path of this element, you can use the solution proposed here: How do you output the current element path in XSLT?.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="text()|@*">
      <xsl:copy>
      <xsl:apply-templates select="node()|@*" />
      </xsl:copy>
  </xsl:template>

  <xsl:template match="//tag">
      <xsl:call-template name="genPath" />
  </xsl:template>

  <xsl:template name="genPath">
      <xsl:param name="prevPath" />
      <xsl:variable name="currPath" select="concat('/',name(),'[',count(preceding-sibling::*[name() = name(current())])+1,']',$prevPath)" />
      <xsl:for-each select="parent::*">
        <xsl:call-template name="genPath">
          <xsl:with-param name="prevPath" select="$currPath" />
        </xsl:call-template>
      </xsl:for-each>
      <xsl:if test="not(parent::*)">
        <xsl:value-of select="$currPath" />      
      </xsl:if>
  </xsl:template>

</xsl:stylesheet>

You can see an example of this here: http://fiddle.frameless.io/

Community
  • 1
  • 1
JohnLBevan
  • 22,735
  • 13
  • 96
  • 178