OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

XSLT's Template Dispatch




Following is a collection of my observations 
regarding XSLT template mechanism.  I hope it may 
be interesting. 

... 

XSLT's Template Dispatch

   by Clark C. Evans
   December 1, 2000

   XSLT is a language for transforming XML texts. The
   language includes familiar constructs such as for-each
   iteration, conditional statements, and callable
   functions. XSLT also includes an additional control
   structure, the template dispatch, which occurs through
   the interaction of apply-template/select and
   template/match. 

   This paper presents two templates, one of which uses 
   the template dispatch, and a second, functionally equivalent 
   to the first, which is constructed without the help of this 
   control structure.  This paper then concludes with a comparison 
   which may help to elucidate the power and elegance of XSLT's
   template dispatch.

   Consider the XML input

<bookcase>
  <book>
    <title>The C Programming Language</title>
    <author>Brian W. Kernighan</author>
    <author>Dennis M. Richie</author>
  </book>
  <book>
    <title>Compilers: Principles, Techniques, and Tools</title>
    <author>Alfred V. Aho</author>
    <author>Ravi Sethi</author>
    <author>Jeffrey D. Ullman</author>
  </book>
</bookcase>

   processed by the XSLT stylesheet

<stylesheet
  xmlns="http://www.w3.org/1999/XSL/Transform"
  version="1.0">
  <template match="author">
        Author: <apply-templates/>
  </template>
  <template match="book">
      Book: <apply-templates select="title|author" />
  </template>
</stylesheet>

   to produce the following output:

    Book: The C Programming Language
      Author: Brian W. Kernighan
      Author: Dennis M. Richie

    Book: Compilers: Principles, Techniques, and Tools
      Author: Alfred V. Aho
      Author: Ravi Sethi
      Author: Jeffrey D. Ullman

   Given any input text, the following stylesheet will
   produce exactly the same output as the stylesheet above,
   only it will do so without the aid of
   apply-template/select and apply-template/match. As a
   consequence, much of its code necessarily emulates
   functionality required by the XSLT specification and
   built into a compliant XSLT processor.

<stylesheet
  xmlns="http://www.w3.org/1999/XSL/Transform"
  version="1.0">
  <template match="/">
    <call-template name="dispatch"/>
  </template>
  <template name="dispatch">
    <variable name="id" select="generate-id(.)" />
    <choose>
      <when test="//author[generate-id(.) = $id]">
        Author: <call-template name="apply" />
      </when>
      <when test="//book[generate-id(.) = $id]">
      Book: <call-template name="apply" >
              <with-param name="select" select="title|author" />
            </call-template>
      </when>
      <when test="self::text()">
        <value-of select="." />
      </when>
      <otherwise>
        <call-template name="apply" />
      </otherwise>
    </choose>
  </template>  
  <template name="apply">
    <param name="select" select="node()" />
    <for-each select="$select">
    <call-template name="dispatch" />
    </for-each>
  </template>
</stylesheet>


   The entry point for a procedural stylesheet is marked by
   <template match="/">, a special case similar to a "C"
   style main() function. When this template is executed,
   the current node for the process is initialized to root
   node, and then the body, <call-template name="dispatch" />, 
   transfers control to the template named dispatch.

   The dispatch template begins by creating a variable,
   $id, which is used to hold an unique string identifier
   generated by the XSLT processor for the current node.
   Following is a conditional switch statement having three
   when clauses and a single otherwise. For each when
   clause, a path expression is evaluated and converted
   into a boolean value. If true, then the corresponding
   body is executed and control resumes immediately after
   the choose construct ends. If all of the when clauses
   fail to fire, then the body of the otherwise is executed.

   The first case, <when
   test="//author[generate-id(.)=$id]">, has a path
   expression returning the node-set consisting of any
   author element having an identifier equal to the current
   node's identifier. Therefore, if the current node
   happens to be an author, the node-set returned will be
   non-empty, which converts to a true boolean value. This
   body is executed with two operations: the non-empty text
   node "\n Author: " is printed and then control is
   transferred to the apply template as specified by
   <call-template name="apply"/>.

   The second case, <when
   test="//book[generate-id(.)=$id]">, is very similar.
   Only here, the apply template is called with a parameter
   named select. The select parameter is the node-set
   containing all element children of the current node with
   a name of either title or author.

   The third case, <when test="self::text()">, only fires
   when the current node is a text node. Here <value-of select=".">
   instructs the processor to print the text value of the current 
   node.  Finally, in default, the apply template is called when 
   none of the previous when clauses have executed.

   The last template in the procedural stylesheet, apply,
   has an optional parameter select, which is passed as a
   node-set. If this parameter is missing, then every child
   of the current node is selected. The remainder of this
   function then iterates through the selected node-set,
   calling the dispatch template.

   A comparison of the two stylesheets reveals that the
   first when clause described above corresponds directly
   to the first template of the original stylesheet. In a
   similar manner, the second when clause corresponds to
   the second template of the original stylesheet. The
   third when and the default otherwise clause are needed
   to emulate the built-in-rule required by the XSLT
   specification. A fully compliant emulation would also
   order the tests according to XSLT's priority rules.

   As you can see with this emulation, a good amount of
   code is built into the XSLT processor. Specifically,
   functionality similar to the apply template, a default
   entry point, and a mechanism similar to the dispatch
   template are included. Furthermore, the complexity of
   this dispatch mechanism increases when the import
   statement and mode attribute are considered. The
   administration of these and other details is handled by
   the XSLT processor, allowing succinct stylesheets like
   the first one presented.

   Examination of this procedural stylesheet also clarifies
   the complementary roles played by select and match
   expressions. The select expression chooses which nodes
   to visit, and, for each node, the match expressions
   designate which template to execute. This allows an
   ordered set to be selected as a whole, yet each node in
   the set to be treated individually. This decoupling of
   roles is elegantly managed by the XSLT processor and
   invoked by apply-template/select and template/match.

   The decoupling of select and match also allows a
   processor to pre-compute the match expressions up-front.
   For example, given an in-memory node-based implementation,
   an additional pointer could be added to each node. After 
   the tree is loaded and before processing commences, the 
   processor could visit each node in the tree, filling in 
   a pointer to the template which best matches the node 
   according to the priority rules. Then, while iterating 
   through a selected node-set, the template to dispatch is 
   immediately available without further computation.

   XSLT's template mechanism may not be the best solution
   to every transformation requirement; however, when the
   inputs have varying structure such that relative order
   among nodes with different matching criteria is important, 
   its template dispatch approach is a clear winner.