Re: [xsl] xpath query

Subject: Re: [xsl] xpath query
From: Abel Braaksma <abel.online@xxxxxxxxx>
Date: Sat, 19 Jan 2008 01:56:47 +0100
Sean Tiley wrote:
Hi there,
I am still struggling with mostof this stuff, but I have a question
related to the original data.

Are you by any chance the same one as the original poster, who posted to this list with the same subjectline and the same data (going by and signing by the name "Senthil Nathan R")?



If I create the following stylesheet I get 100 100 output


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="2.0">
    <xsl:template match="ROOT">
        <html>
            <xsl:value-of select="LEVEL2/*/*[@apply='1']"/>
        </html>
    </xsl:template>
</xsl:stylesheet>

What I am not clear on is why does this return values and not nodes?

That is why the instruction is called "value-of": that means, like you said, that it will return values, and not nodes. If you want nodes, you must use xsl:copy-of instead.


Or is this really returning both nodes and I am getting the value of
each one because of the <xsl:value-of select="..."/> expression?

You are saying it right there. You are getting the "value of" ... because of using the "value-of" instruction... ;)


As far as I can figure the expression ROOT/LEVEL2/*/*[@apply='1']"
says give me the nodes that have the arrtibute apply=1 and are
grandchildren of level2.

Yes, that is precisely what the expression says. But you are mixing the XPath expression and the XSLT instruction here. In XPath you say "give me those nodes", then you instruct XSLT to use the value of those nodes, and not the nodes themselves (again, that would be xsl:copy-of).


I kind of though to get both values I would have to do something like

<xsl:template match="ROOT">
      <xsl:for-each select="LEVEL2/*/*[@apply='1']">
           <xsl:value-of select="."/>
      </xsl:for-each>
</xsl:template>

Sorry if this seems really trivial but it helps me to better understand.

In XSLT 1.0, the first value of a node set was returned, which would be "100" in your case. In XSLT 2.0 (which is what you are using), this changed because the underlying model changed: everything is a sequence now. The resultset of an XPath statement is a sequence of items (nodes, text nodes, attributes, strings etc) and the value of these items is taken, and finally these values are separated by whatever is in the attribute "separator":


<xsl:value-of select="(2 to 10)[. le 5]" separator=":" />

will output the string "2:3:4:5" (i.e., all values lower or equal to five, separated by the colon).

The for-each is hardly ever necessary and I believe it is often over-used. Instead of for-each you can just as well use xsl:apply-templates. There are, however, exceptions (notably: for-each can work on any item type, whereas apply-templates only works on a nodeset). Depending on what you want, you are right by your statement that you need something to iterate over, or apply templates on the nodes in the set. However, if you only need the first node, you can of course use the predicate [1], or another number if you do not want the first:

<xsl:value-of select="*[@apply='1'][1]" />

I think many people find this at first confusing: when do you get a node set, when do you get one node, when do you get a sequence or a sequence of nodes, when do you need apply-templates, when for-each or for-each-group etc etc. Getting it straight is vital for working with XSLT without frustration.

HTH,
Cheers,
-- Abel Braaksma

Current Thread