Introduction to XSLT

Jean-François Perrot

  1. General idea & History
    1. Markup Languages, from text to structure
    2. The transform way : XSL eXtensible Stylesheet Language
    3. A programming language in its own right
    4. Example : The Menu

  2. Basic theory
    1. A rule-based language
      1. Rule = condition - action
      2. Recursive call of the rule base
      3. Default rules
    2. Two uses of XPath expressions
    3. Traditional control structures
    4. A useful feature : sorting

  3. Advanced theory
    1. XML namespaces
    2. Generating XML


  1. General idea & History


  2. Basic theory

    (illustrated with HTML generation for  the name/mark example)

    An XSLT program ( = stylesheet) is
    1. A rule-based language

      Provisionally, consider that at most one rule can be applied to any XML object in the document.
      The matter of rule priority in XSLT is treated in a counter-intuitive way, and should be left aside at an introductive level.
      1. Rule = condition - action
        <xsl:template match="condition">
            action
        </xsl:template>


        • condition is an expression in the XPath language.
          Such an expression describes a set of paths in the XML tree, with a Unix-like syntax.
          The condition is true for a given node N if N belongs to the set of nodes that are reachable by one of those paths.

          Examples :
          • "/" is the Document node,
            a rule starting with <xsl:template match="/"> is applicable to this node only.

          • "student" denotes any Element node with name (tag) "student" which is a child of the current node.

        • action is a text in which
          • fragments tagged <xsl:... > are XSLT instructions and are evaluated
          • all other fragments make up a tree-like structure (XML, HTML or text), which may be
            • either directly processed (e.g. in a browser)
            • or sent to the output medium
              where it will be serialized according to the option that is fixed in the <xsl:output> tag.

        • Example : list.xsl  to be applied to an name/mark file with DTD #2 (e.g. Nom_note2_list.xml)

          <?xml version='1.0'?>
          <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'>
          <xsl:output method="html" />

          <xsl:template match="/">
            <html><head><title>Visualisation</title></head>
             <body>
              <h2>Here is a list of names and marks</h2>
              <ol>
                  <xsl:apply-templates/>
              </ol>
             </body>
            </html>
          </xsl:template>

          <xsl:template match="student">
               <li>
                  <xsl:value-of select="name"/> : <xsl:value-of select="mark"/>
               </li>
          </xsl:template>

          </xsl:stylesheet>


          Execution :
          1. The first rule is applied to the Document node.
            This application first generates the tree fragment
            <html><head><title>Visualisation</title></head>
               <body>
                <h2>Here is a list of names and marks</h2>
                <ol>

          2. then <xsl:apply-templates/> is executed (see below)
          3. on the return of <xsl:apply-templates/>, the following tree fragment is generated
                </ol>
               </body>
              </html>


          4. <xsl:apply-templates/> will ultimately cause the 2nd rule to be applied to each <eleve> node in turn.
            Each application will
            1. first generate <li>
            2. then evaluate <xsl:value-of select="name"/>
            3. generate " : "
            4. then evaluate <xsl:value-of select="mark"/>
            5. finally generate </li>

          5. Evaluating <xsl:value-of select="tagName"/> yields the complete subtree contained in the first child node
            of the current node that bears the tagName.
            <xsl:value-of select="name"/> will yield Toto or the first <student>, then Tata, etc.

          The total output will be

          <html><head><title>Visualisation</title></head>
          <body>
              <h2>Here is a list of names and marks</h2>
              <ol>
                  <li> Toto : 12 </li>
                  <li> Tata : 13 </li>
                  <li> Tutu : 17 </li>
                  <li> Titi : 11 </li>
              </ol>
          </body>
          </html>



      2. Recursive call of the rule base
        The most fundamental instruction is <xsl:apply-templates />
        which launches the whole rule base on the children of the current node.
        A variant is <xsl:apply-templates select="an-XPath-expression" />
        which restricts the application domain to the set of nodes that is the value of the expression at the present node.
        The short form <xsl:apply-templates /> is equivalent to <xsl:apply-templates select="*" />.

        Execution starts by applying the rule base to the Document node
        (hence the utility of a rule with <xsl:template match="/">)
        and proceeds by recursive calls in a descending way on the tree structure.

        On our example, there is a rule for the Document node, but none for its only child <liste>.
        Does computation stop there ?
      3. Default rules
        To facilitate the writing of rule bases in an intuitive way, the default rules will
        for any node to which no explicit rule is applicable
        1. Output the complete text contained in it.
        2. Execute <xsl:apply-templates />, i.e. launch the rule base on its children.

        In our case, this will launch the rule base on the children of <liste>, i.e. the <eleve>,
        for which there is an applicable rule !
    2. Two uses of XPath expressions

      XPath expressions play in XSLT a dual role :

      1. Producing sets of nodes, as in <xsl:template match="expression"> or in <xsl:apply-templates select="expression" />:
        • /list/student = all <student> from the root "/"
        • student/mark = all <mark> from the  <student> where evaluation occurs
        • list/student[position() = last()] = the last <student > in  <list>
          see listSep.xsl 
        • list/student[@name = 'Toto'] = all <student> children of  <list> whose attribute name is Toto (Names & Marks #1)
          Beware ! This expression will be written as a string value of an attribute (match or select), i.e. between double quotes,
          hence 'Toto' between simple quotes !

      2. Yielding a (terminal) string value in <xsl:value-of select="expression" />
        to be combined with other (constant) strings to build the final value of an <xsl:apply-templates /> call.

        • Evaluation of <xsl:value-of select="@attributeName"/> yields the value of the attribute of the current node
          with name attributeName.
          See tableAt.xsl
        • <xsl:value-of select="sum(/list/student/@mark) div count(/list/student)" />
          computes the average, from the root.
          See moy.xsl

    3. Traditional control structures

      To deal with cases where the subtle play of templates seems impractical,
      programmers may fall back on the usual control structures :

      1. One-way conditional construct
        <xsl:if test="boolean-valued XPath expr.">
             action
        </xsl:if>

        Example.

      2. Multiple  choice
        <xsl:choose>
           <xsl:when test
        ="boolean-valued XPath expr.">
             action
           </xsl:when>
           <xsl:when test="boolean-valued XPath expr.">
             action
           </xsl:when>
           ............
           <xsl:otherwise>
             action
           </xsl:otherwise>
        </xsl:choose>

        Example.

      3. for-each loop
        <xsl:for-each select="nodeSet-valued XPath expr.">
            action
        </xsl:for-each>

        Example.

    4. A useful feature : sorting

      1. <xsl:sort select="criterium" /> inside an <xsl:apply-templates> or an <xsl:for-each>
        will induce a sorted treatment according to the criterium feature, if it is available !
        By default alphabetical sorting is applied
        e.g.
               <xsl:apply-templates>
                     <xsl:sort select="@name" />
           </xsl:apply-templates>

        will deal with (presumably, eleves) following the alphabetical order of their names.
        Example

      2. Additional information about the sorting method :
        ex. <xsl:sort select="mark" order="descending" data-type="number"/>
        default values : ascending and text.
        Example.
        read more...

  3. Advanced theory

    1. XML namespaces

      • Declared in the root tag, together with the xslt ns.
      • All other namespaces apply to the source document and to the target document alike.
      • A default namespace may be used only for the target document.

      Example : To generate an XHTML page from Names & Marks in RDF format, the root tag will be :

      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'
             xmlns="http://www.w3.org/1999/xhtml"
             xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
             xmlns:epita="http://epita/masters/international/">


    2. Generating XML

      1. Tags and attributes of the target document are written in the same way as HTML in our previous examples
        if they are constant.

      2. Quite often, attributes values must be computed. Then, use an explicit construction :
                <myTag>
                <xsl:attribute name= "name-of-attribute">
                     ... computation of value, typically ....
                     <xsl:value-of select="some-XPath-expression"/>
                     ...........
                </xsl:attribute>
             </myTag>


        see examples here.

      3. When the computation of the attribute value is easy, use a shorthand
        (note the  curly brackets inside the double quotes of the value string )

        <myTag myAttribute="{some-XPath-expression}">
              ....
        </myTag>


        see an example here.

      4. Very rarely, attribute names or even tag names must be computed.
        Then use the heavy DOM-like artillery :
            <xsl:element name="{some-XPath-expression}">
                <xsl:attribute name="{another-XPath-expression}">
                    ... computation of attribute value ...
                </xsl:attribute>
               .... computation of element contents ...
            </xsl:element>


        see an example here.