3

I am having trouble understanding how the exsl:node-set function works.

I have some XML which I am expanding and using to dynamically populate an exsl:node-set. Let's say it currently is in this format:

<xsl:variable name="wrap">
    <nodes>
        <node/>
        <node/>
        <node/>
    </nodes>
</xsl:variable>
<xsl:variable name="wrapNodeSet" select="exsl:node-set($wrap)"/>

This works as required and outputting $wrapNodeSet shows the nodes markup above. Root node name is show as 'nodes' using name($wrapNodeSet/*).

Now I need to expand this to have 2 nodes and to populate the nodeset dynamically. So:

    <xsl:variable name="wrap">
    <nodes tier="a">
        <node/>
        <node/>
        <node/>
    </nodes>
    <nodes tier="b">
        <node/>
        <node/>
        <node/>
    </nodes>
</xsl:variable>
<xsl:variable name="wrapNodeSet" select="exsl:node-set($wrap)/nodes[@tier='b']"/>

Outputting the node set includes the nodes element but outputting the name of the root node now changes to 'node'.

Can someone explain why the nodes element is still output?

Alex B
  • 1,009
  • 3
  • 18
  • 26

3 Answers3

0

If I've understood your question correctly, I believe 'intuitively' what's happening (the actual behind-the-scenes implementation details are probably a bit different) is in the first instance, your variable points to the 'anonymous node set' of the variable that wraps the <nodes> element. So doing name($wrapNodeSet/*) gets the names of all direct children of this anonymous node set, which in this case is just the name of the single <nodes> element.

In the second case, you've gone deeper than the anonymous node set and the variable contains the single nodes[@tier='b'] element directly. In this case name($wrapNodeSet/*) selects all direct children of that <nodes> element instead, and will return 3 instances of <node>. If you do a value-of select on this, it will default to displaying just the first one, which is why you'll just see "node" in the output.

To get the name of the root for the second instance, just do name($wrapNodeSet) directly and you should see "nodes". Doing $name(wrapNodeSet) in the first instance will not return anything, as the anonymous node set does not have a name.

actionshrimp
  • 5,219
  • 3
  • 23
  • 26
0
<xsl:variable name="wrapNodeSet" 
              select="exsl:node-set($wrap)/nodes[@tier='b']"/>

This selects any nodes element from the tree obtained with the node-set() extension, that (the nodes element) has a tier attribute with value 'b'.

Then:

name($wrapNodeSet/*)

produces the name of the first child-element of the first node contained in $wrapNodeSet. As $wrapNodeSet contains exactly one nodes element, and the nodes element has only node child-elements, the first such child element is a node element and its name, as the name of any node element is "node".

Why do you see anything unexpected in this result?

In other words:

The application of ext:node-set() on $wrap in both cases produces the same tree, but in the second case you use a different, longer XPath expression on the result of ext:node-set($wrap) -- hence the different result you get from the evaluation of those two different XPath expressions.

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
0

exslt:node-set has a very informal specification and there are probably details on which implementations differ from each other. This is certainly so in edge cases, such as what happens if the argument to exstl:node-set is something other than a result tree fragment.

The behaviour I would expect is that exslt:node-set() always delivers a "root node" (what XPath 2.0 calls a "document node"). A root node as defined in XPath 1.0 has no name. In your first example the root node has one element child whose name is "nodes". In your second example the root node has two element children, both of which have the name "nodes".

You say "outputting the name of the root node now changes to 'node'" - which is confusing, because a "root node" as XPath 1.0 defines the term never has a name. What did you actually output?

Michael Kay
  • 156,231
  • 11
  • 92
  • 164