Friday, March 4, 2011

Can't stop thinking about XSLT in procedural terms... help with apply-templates.

I know that XSLT does not work in procedural terms, but unfortunately I have been doing procedural languages for too long. Can anyone help me out by explaining in simple terms how things like apply-templates works and help a thicko like me to understand it.

From stackoverflow
  • I wrote a blog entry ages ago that shows a simple stylesheet written in a 'procedural' style using xsl:for-each and the equivalent using xsl:apply-templates. It's by no means a comprehensive guide but hopefully it will be of some use.

    annakata : I'm not sure I agree with the sentiment - for-each structures are *much* easier for !XSLT guys to understand and XSLT is seen as voodoo by too many already (readability counts) - but it's a well written piece
    Xetius : This does start to diminish the mysticism surrounding the magical apply-templates for me. Also, I have just found that stepping through examples using Visual Studio (2008) has helped too.
    Dimitre Novatchev : Fully agree with the blog post. For more details on this subject, see my answer.
  • What makes you think that procedural terms do not apply here? It's just that the calling convention is somewhat more implicit than you would traditionally expect it, because there is an invisible context involved. Everything apply-templates does could be expressed in procedural terms.

    Basically, apply-templates is nothing more than a for-each loop. Starting from where where you currently are in the document (the context, think "this"), it iterates over the child nodes.

    For each child, the processor selects the matching xsl:template with the highest priority (based on their respective match and priority attributes), sets the context to the child at hand and runs this template (think "function"). After the template returns, the context snaps back and it's the next child's turn.

    Even when things become recursive (which is somewhat hard to avoid in XSLT), the whole process really does not become any more complicated. The context "pointer" is moved around, and templates get called.

    You can restrict the node set that apply-templates iterates over, using the select attribute:

    <!-- all children of the context node regardless -->
    <xsl:apply-templates />  
    
    <!-- all children of the context node being "data" with a @name of "Foo" -->
    <xsl:apply-templates select="data[@name='Foo']" />  
    

    You can sort the node-set prior to the iteration, if you wish:

    <!-- all children of the context node being "data" with a @name of "Foo",
         ordered by their respective "detail" count -->
    <xsl:apply-templates select="data[@name='Foo']"> 
      <xsl:sort select="count(detail)" data-type="number" order="descending"/>
    </xsl:apply-templates>
    

    And you can pass parameters to your template if you need, just like you would with a regular function call:

    <!-- pass in some parameter -->
    <xsl:apply-templates select="data[@name='Foo']"> 
      <xsl:with-param name="DateSetIcon" select="$img_src" />
    </xsl:apply-templates>
    

    That's about all there is to it.

    EDIT:

    I know that the last comment is a bit provocative. This is very much intentional, for a basic understanding of how apply-templates works this is more or less it. The implications and possibilities that come from the fact that not you are defining what template to call, but rather let the processor choose the right one for you are of course bigger than what it sounds like to the untrained ear. The declarative/implicit approach of the whole thing surely needs some time to sink in.

    Dimitre Novatchev : "That's about all there is to it"... Not exactly, see my answer.
  • I strongly agree with the answer and blog post of Greg Beech.

    For more detailed comparison between <xsl:for-each> and <xsl:apply-templates> see my answer to the question "xsl:for-each vs. xsl:apply-templates" in the xsl-list, and enjoy the whole thread.

    "xsl:apply-templates is much richer and deeper than xsl:for-each, even simply because we don't know what code will be applied on the nodes of the selection -- in the general case this code will be different for different nodes of the node-list. Also, the code that will be applied can be written way after the xsl:apply templates was written and by people that do not know the original author".

    Another difference from a procedural programming language is that the order in which the templates will be applied is not predefined. There is no notion of "state" or "order of execution" in a pure functional programming language.

    Neither XSLT 2.0 nor XSLT 1.0 specifies any particular order of applying the selected template rules -- only that their results will be combined according to the order of the nodes (in the sorted sequence, if there are any <xsl:sort> directives or otherwise in the document order of the nodes), on which the templates are applied.

    The XSLT 2.0 Spec says:

    "Each template rule that is evaluated produces a sequence of items as its result. The resulting sequences (one for each node in the sorted sequence) are then concatenated, to form a single sequence. They are concatenated retaining the order of the nodes in the sorted sequence. The final concatenated sequence forms the result of the xsl:apply-templates instruction"

    The XSLT 1.0 spec says:

    "Implementations are free to process the source document in any way that produces the same result as if it were processed using this processing model."

    It is even possible that an XSLT implementation may apply templates (or the body of an <xsl:for-each>) in parallel.

    Tomalak : I don't see what would be incorrect in my answer. You add details on execution order, but for the transformation result (and anything else, XSL should be side-effect free) execution order is irrelevant, or is it not? My "about that's all there is" maybe provocative, but what else is there?
    Dimitre Novatchev : Tomalak, my comment was: ""That's about all there is to it"... Not exactly, see my answer". I didn't ever say your answer was incorrect. Simply, is a much bigger topic. Cheers
    Tomalak : I imagined that "not exactly" would be a friendlier way of saying "that's wrong" (it usually is in the English-speaking world).
    Tomalak : (And, putting two and two together, I thought that the down-vote was yours and that there must be an error in my answer.)
    Dimitre Novatchev : Hey, I haven't downvoted for a long time! :) Thanks for reminding me. And no, I didn't even know (no way to see it) that your answer was downvoted. Do you want to verify this? I can send you a screenshot of my "Votes" tab. Cheers
    Tomalak : Not necessary, I believe you! ;-) It's no big deal anyway. Sometimes down-votes can be aligned to "I don't think so" comments, so it just seemed likely. It's too bad that down-votes often come with no explanation.
    Dimitre Novatchev : Yes, I think it would be good if SO changes the way of downvoting by making an explanation mandatory. Maybe even show the userid of the downvoter.
    Tomalak : This would only work if every user was sensible and fair, which can safely be ruled out. Many users would switch to an "an eye for an eye" mode... Unfortunately nobody can seem to think of a workable alternative, various suggestions on Uservoice have been made, but all were flawed some way or other.

0 comments:

Post a Comment