xsl-list
[Top] [All Lists]

Re: [xsl] node() function

2014-06-23 21:01:48
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 = “_xpath_to_c”/>

           </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(_at_)exselt(_dot_)net 
<xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com> wrote:
Hi Dak,

Please see my answers inline,

Cheers,

Abel Braaksma
Exselt XSLT 3.0 streaming processor
http://exselt.net

Mailing Lists Mail daktapaal(_at_)gmail(_dot_)com
<mailto:xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com>
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 haven’t 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 = “c”/>
</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.




<!—Other 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


--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--

<Prev in Thread] Current Thread [Next in Thread>