Re: [xsl] node() function

Subject: Re: [xsl] node() function
From: "Mailing Lists Mail daktapaal@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 24 Jun 2014 02:01:36 -0000
Very Logically True. Thanks Abel.
Just a quick clarification..

when I meant intuitive with approach1, I gave a wrong example..

I meant something like :

           <xsl:template match="/">

            <xsl:apply-templates select = b_xpath_to_cb/>

           </xsl:template>

<xsl:template match="c">

<xsl:value-of select="."/>

</xsl:template>


Dont you think it is more intuitive to say :
1.  "Go Process all the c nodes at the xpath_to_c"
Than to say
2.  visit *every* node and delete it  if you dont find a matching node

Dont you think the option1 above is direct to the point, if that is
what I want? If there are 1000s of nodes in the document tree, then
dont you think it will take one hell of a time to visit
*each_and_every* node and deleting it, if the node is not matched..
Some how pointing it to the right xpath makes more efficient sence?

Dak.T


On Mon, Jun 23, 2014 at 8:01 PM, Abel Braaksma (Exselt)
abel@xxxxxxxxxx <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
> Hi Dak,
>
> Please see my answers inline,
>
> Cheers,
>
> Abel Braaksma
> Exselt XSLT 3.0 streaming processor
> http://exselt.net
>
>> Mailing Lists Mail daktapaal@xxxxxxxxx
>> <mailto:xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
>> maandag 23 juni 2014 22:17
>>
>>
>> <xsl:template match="node()|@*">
>> <xsl:apply-templates/>
>> </xsl:template>
>>
> The expression "node()" is not a function, it is a node-test, similar to
> "foo" (tests for an element with the name 'foo') or "comment()" (tests for
> comment nodes). The template is matched when _any_ node is found. Since
> inside the body of the template you only have an xsl:apply-templates and
the
> only template in existence is that very template, the stylesheet as a whole
> will not output anything: a so-called "delete-template".
>
> Remember that when you do apply-templates without argument, you select all
> children (but not attributes) and ask the processor to find matching
> templates. In this case, this is the template with match="node()", which
> means "match anything, including text, comment and PI nodes, except
> attributes". The part of the expression that matches attributes has not
> effect, because you do not apply templates on attributes.
>
>>
>> <xsl:template match="*">
>> <xsl:apply-templates/>
>> </xsl:template>
>> </xsl:stylesheet>
>>
> This looks similar, but is not. The match="*" only matches elements. That
> means, that if the xsl:apply-templates encounters text nodes, there is no
> matching template, so the default template will kick in. That is the reason
> why this one does, and the previous one does not give you text output.
>
>
>>
>> <xsl:template match="/">
>> <xsl:apply-templates/>
>> </xsl:template>
>> </xsl:stylesheet>
>
>
> This looks similar, but is totally different. With one input document there
> will usually be only one root node that can ever be matched. The expression
> "/" matches that root node. Your template will be hit once, the
> apply-templates selects its children, which do not have a matching
template,
> so the default templates kick in: text is output, similar, but not the
same,
> as with the previous code, your #2.
>
>
>>
>> I was expecting all the three stylesheets to copy the text nodes to the
>> target.
>
>
> No, only the last two, the first was different, it was written to delete
all
> content of the input document.
>
>>
>> While the stylesheet2 and stylesheet 3 did that, the stylesheet 1 did
>> not output anything ( wondered why?? )..
>>
>> What I was thinking the stylesheet1 will do is :
>>
>> 1. Match any node() or the attribute node .
>
>
> That is correct, that is what it did.
>
>>
>> 2. Apply template to the children and self
>
>
> No, you only applied templates to the children if each current node
> recursively, not to self (which would have led to an eternal loop if you
did
> that).
>
>>
>> 3. Default template rule will kick in as I havenbt mentioned
>> any node. This will :
>
>
> Yes you "mentioned" a node: any node, to be precise: every node is matched
> if you use node().
>
>>
>> a. Do value-of select for text nodes
>
>
> Yes, but you specified differently, so the default template never kicked
in.
>
>>
>> b. Do apply-templates for the element nodes ( * )
>
>
> No, it would do apply-templates for all nodes, except attribute nodes.
>
>> SO the answer was in the fact that node() does not match text()??
>
>
> No, the answer was that "node()" _also_ matches text-nodes. It matches
every
> node. But you did not do a value-of yourself inside your template, so
> nothing was output.
>
>>
>> So I added
>> <xsl:template match="text()">
>> <xsl:value-of select="."/>
>> </xsl:template>
>
>
> Yes, that works. Now you specified _explicitly_ to make an exception for
> text-nodes, which takes precedence over your match="node()", so the result
> is that the text is matched in the added template, and your value-of makes
> sure that the text is output.
>
>>
>> This came with what I wanted.. ( both happy and disappointed )
>>
>> Happy as it brought me to a logical end, and disappointed as it dint
>> work like I initially thought it would.
>>
> Hope that the above explanations helped a bit.
>
>
>>
>> Further, This leads me to a (dangerous) way of saying : Select only
>> node c and nothing else.
>
>
> The XSLT way of doing that is: write a delete-template (your example #1
> above) and add an exception for the c-node, full stylesheet body could look
> like this:
>
>
> <xsl:template match="node()|@*">
> <xsl:apply-templates/>
> </xsl:template>
>
> <xsl:template match="c">
> <!-- copy all children, do not process children further -->
> <xsl:copy-of select="." />
> </xsl:template>
>
> Your original example serves as a "delete everything", so all you need to
do
> is specify what you do not want to delete, and copy that. Instead of
> xsl:copy-of you can also do xsl:value-of or do some further processing on
> the children. That is the beauty of XSLT: you specify with templates what
> you want output, the processor does the necessary processing logic behind
> the scenes.
>
>
>> I could do :
>> 1. The normal intuitive way ( Approach A)
>> <xsl:template match="/">
>> <xsl:apply-templates select = bcb/>
>> </xsl:template>
>> <xsl:template match="c">
>> <xsl:value-of select="."/>
>> </xsl:template>
>
>
> Not sure this is the "normal intuitive way" in XSLT. It only works if you
> have a root node called "c", no other nodes will ever be processed (you
> match "/", and then you tell the processor to select "c" children, which
can
> at most be one, because the root node can have only one child).
>
>
>> 2. The somewhat dangerous way (based on the observation in PART1
>> ) ( Approach B )
>>
>> <xsl:template match="node()|@*">
>> <xsl:apply-templates/>
>> </xsl:template>
>> <xsl:template match="c">
>> <result>
>> <xsl:value-of select="."/>
>> </result>
>> </xsl:template>
>
>
> No, this is the _safe_ way, not the dangerous way. Your observation led you
> to the wrong conclusions, but to the correct solution. This is precisely
how
> you would specify it in XSLT.
>
>>
>>
>>
>> <!bOther nodes will not be cared for or other nodes does nothing (but
>> why??)
>>
>> I would have thought, the other nodes will be matched, and text nodes
>> be printed, but did not, as in PART1. (= reasons for calling Part 2
>> as corollary to part 1)
>
>
> Yes, other nodes (all nodes) are matched, every time, inside the
> match="node()|@*" template. But there is no xsl:value-of or xsl:copy or
> anything that creates output, so the result is empty, except, in your last
> example, for the (text value of the) c-element.
>
>>
>> Approach B is not intuitive for me. But somehow doing the same thing
>> as approach A. Although I will NEVER use the approach B.
>
>
> Welcome to the world of XSLT: instead of writing step by step what you want
> the processor to do (your approach A, which is not flexible and will hardly
> ever work), you can write templates, and the processor will simply process
> your templates when it finds nodes that match them. In fact, you tell in
> your stylesheet how you want the output to look like based on certain input
> (which you specify in the match-attribute) and the processor does the heavy
> lifting for you. Result: no loops required, no recursion required to
process
> children and children of children, nothing of the kind.
>
> May I suggest taking a little moment of reading a few chapters of an XSLT
> beginners book? The ones by Jeni Tennison are still excellent material. It
> explains this way of thinking and once you get the hang of it you wonder
why
> you ever wanted to do it differently ;).
>
>
>> Any Idea why this is so.. are there situations where approach B wont
>> work? I want to think approach B is Wrong and will fail some how..
>
> Anything can go wrong, depending on how you program, what your requirements
> are. XSLT is a powerful language and as with any programming language, a
> programmer will, at one point or another, introduce bugs in a program,
> usually when the program code starts to grow beyond the mere trivial.
>
> But if the requirement is "output the text value of node X" then approach B
> is excellent. In fact, in most cases, you either choose an approach B of
the
> form "delete everything, and keep this and that", or "copy everything, but
> delete this and that" (which is commonly referred to as the "XSLT copy
> idiom", but that is excellently covered in the XSLT Cookbook, 1st edition
> for XSLT 1.0 and 2nd edition for XSLT 2.0, both are available online free
of
> charge).
>
> Cheers,
> Abel

Current Thread