Re: [xsl] node() function
2014-06-23 19:01:59
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
--~--
|
|