6

I have a document that looks something like

<root>
    <element>
        <subelement1 />
        <subelement2 />
    </element>
    <element>
        <subelement2 />
        <subelement1 />
    </element>
</root>

In my XSLT sheet in the context of /element[2]/[someNode] I want to get a number that represents the distance of /element[1]/[someNode] (ie, the number of preceding siblings of /element1/[someNode]). For example, in the context of /element[2]/subelement1 I'd like to have some way to get the number 2, the distance from /element[1] to /element[1]/subelement2. I only ever need the distance of the given node name from the first instance of <element>.

Intuitively I thought I could construct this like

 <xsl:variable name="nodename" select="name()" />
 <xsl:value-of select="/element[1]/$nodename/preceding-sibling::*" />

but unfortunately this sheet doesn't compile. Is what I'm trying to achieve possible in XSLT?

2
  • Your example seems inconsistent: in the context of /element[2]/[someNode] you want to find /element[1]/[someNode] with as example in /element[2]/subelement1 you want to find the distance from /element[1] to /element[1]/subelement2 - so is [someNode] here subelement2 or subelement1? Commented Mar 21, 2010 at 12:45
  • See also stackoverflow.com/questions/4630023/dynamic-xpath-in-xslt Commented Sep 12, 2014 at 12:36

3 Answers 3

8
  1. You cannot use an XSLT variable as the axis of an XPATH statement, but you can use it in a predicate filter. So, if you were to match on any element (i.e. *) and then restrict it to elements who's name() is equal to the value stored in your variable (i.e. *[name()=$nodename]) the XPATH will be valid.

  2. The XPATH you were constructing would return the value of the matching element. If you want to return how many elements match that pattern, you can use the count() function.

  3. Your example XML has a document element <root>, but your XPATH does not include <root>.

This returns the number of preceding-sibling elements using the variable assigned by the context node:

<xsl:variable name="nodename" select="name()" />
<xsl:value-of select="count(/root/element[1]/*[name()=$nodename]/preceding-sibling::*)" />

You could eliminate the variable and just use:

<xsl:value-of select="count(/root/element[1]/*[name()=name(current())]/preceding-sibling::*)" />
Sign up to request clarification or add additional context in comments.

Comments

1

*[name() = $nodename] might be what you want instead of $nodename but you should then better define two variables with the value of local-name() and namespace-uri() and check e.g. *[local-name() = $localname and namespace-uri() = $namespaceuri] to have a namespace safe way of selecting elements.

Comments

0

Build xpath's is unfortunately impossible. XPaths are statically compiled; you cannot generate them on the fly (or if you do, they're just strings and cannot be executed).

However, what you can do is write a query that happens to cross-reference several values which themselves are dynamic...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.