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 |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] node() function, Abel Braaksma (Exsel | Thread | Re: [xsl] node() function, Abel Braaksma (Exsel |
Re: [xsl] node() function, Abel Braaksma (Exsel | Date | Re: [xsl] node() function, Dimitre Novatchev dn |
Month |