XML Transformations (XSLT) — Part III

XML Foundations (INFOSYS 242)

Erik Wilde, UC Berkeley iSchool
Thursday, September 28, 2006
Creative Commons License

This work is licensed under a Creative Commons
Attribution-NonCommercial-ShareAlike 2.5 License.

Abstract

Advanced XSLT processing includes better control of the input and output documents, which can finely controlled in terms of how whitespace is treated. Another interesting feature of XSLT are keys, which allow shorthand notations for frequently used access paths to nodes, and provide XSLT processors with more information for performance optimizations. Instructions for creating all possible kinds of nodes in the output tree make it possible to write code which generates element or attribute names based on runtime evaluations.

XSLT Core Concepts

Outline (Variables and Parameters)

  1. Variables and Parameters [9]
    1. Variables [3]
    2. Parameters [5]
  2. Controlling Documents [6]
    1. Input Documents [3]
    2. Output Documents [2]
  3. Keys [6]
  4. Generating Result Nodes [2]
  5. Modularizing Stylesheets [2]
  6. Conclusions [1]

Programming Language Basics

<xsl:variable name="sum" select="$op1 + $op2"/>
<xsl:variable name="result" select="$sum * $factor"

Outline (Variables)

  1. Variables and Parameters [9]
    1. Variables [3]
    2. Parameters [5]
  2. Controlling Documents [6]
    1. Input Documents [3]
    2. Output Documents [2]
  3. Keys [6]
  4. Generating Result Nodes [2]
  5. Modularizing Stylesheets [2]
  6. Conclusions [1]

Why Variables?

Scope and Extent

Using Variables

 <xsl:variable name="name" select="'value'"/>
 <xsl:template match="/">
  <xsl:choose>
   <xsl:when test="$name = 'value'">
    <xsl:variable name="result" select="'ok'"/>
   </xsl:when>
   <xsl:otherwise>
    <xsl:variable name="result" select="'problem'"/>
   </xsl:otherwise>
  </xsl:choose>
  <xsl:value-of select="$result"/>
 </xsl:template>
 <xsl:variable name="name" select="'value'"/>
 <xsl:template match="/">
  <xsl:variable name="result">
   <xsl:choose>
    <xsl:when test="$name = 'value'">
     <xsl:value-of select="'ok'"/>
    </xsl:when>
    <xsl:otherwise>
     <xsl:value-of select="'problem'"/>
    </xsl:otherwise>
   </xsl:choose>
  </xsl:variable>
  <xsl:value-of select="$result"/>
 </xsl:template>

Outline (Parameters)

  1. Variables and Parameters [9]
    1. Variables [3]
    2. Parameters [5]
  2. Controlling Documents [6]
    1. Input Documents [3]
    2. Output Documents [2]
  3. Keys [6]
  4. Generating Result Nodes [2]
  5. Modularizing Stylesheets [2]
  6. Conclusions [1]

Parameters vs. Variables

Stylesheet Parameters

 <xsl:param name="number" select="0"/>
 <xsl:variable name="number-param">
  <xsl:if test="string(number($number)) = 'NaN'">
   <xsl:message terminate="yes">"number" must be a proper number!</xsl:message>
  </xsl:if>
  <xsl:value-of select="$number"/>
 </xsl:variable>
 <xsl:template match="/">
  <xsl:value-of select="10 * $number-param"/>
 </xsl:template>

Template Parameters

main param start = 1 ; param count = 10 ; {
	loop (0) };
loop param counter ; {
	print $start + $counter ;
	if ( $counter < $count - 1) then 
		loop ($counter + 1) ; }

Parameter Passing

 <xsl:param name="start" select="1"/>
 <xsl:param name="count" select="10"/>
 <xsl:template match="/">
  <xsl:call-template name="loop">
   <xsl:with-param name="counter" select="0"/>
  </xsl:call-template>
 </xsl:template>
 <xsl:template name="loop">
  <xsl:param name="counter"/>
  <xsl:message>
   <xsl:value-of select="$start + $counter"/>
  </xsl:message>
  <xsl:if test="$counter &lt; $count - 1">
   <xsl:call-template name="loop">
    <xsl:with-param name="counter" select="$counter + 1"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>

Message Facility

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="message" select="'plain'"/>
    <!-- messaging style: 'silent', 'plain', or 'prefixed' -->
    <xsl:template name="message">
        <xsl:param name="level" select="'fatal'"/>
        <!-- message level: 'warning', 'error', or 'fatal' -->
        <xsl:param name="text" select="'no text given'"/>
        <xsl:choose>
            <xsl:when test="$message = 'silent'"/>
            <xsl:when test="$level = 'warning'">
                <xsl:call-template name="print_message">
                    <xsl:with-param name="level" select="'warning'"/>
                    <xsl:with-param name="terminate" select="'no'"/>
                    <xsl:with-param name="text" select="$text"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="$level = 'error'">
                <xsl:call-template name="print_message">
                    <xsl:with-param name="level" select="'error'"/>
                    <xsl:with-param name="terminate" select="'no'"/>
                    <xsl:with-param name="text" select="$text"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="$level = 'fatal'">
                <xsl:call-template name="print_message">
                    <xsl:with-param name="level" select="'fatal'"/>
                    <xsl:with-param name="terminate" select="'yes'"/>
                    <xsl:with-param name="text" select="$text"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="print_message">
                    <xsl:with-param name="level" select="'fatal'"/>
                    <xsl:with-param name="terminate" select="'no'"/>
                    <xsl:with-param name="text" select="concat('fatal:unknown level for message [', $text, ']')"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template name="print_message">
        <!-- this template should never be called from outside; for printing messages, call the "message" template. -->
        <xsl:param name="level"/>
        <xsl:param name="terminate"/>
        <xsl:param name="text"/>
        <xsl:choose>
            <xsl:when test="$message = 'plain'">
                <xsl:message terminate="{$terminate}">
                    <xsl:value-of select="$text"/>
                </xsl:message>
            </xsl:when>
            <xsl:otherwise>
                <xsl:message terminate="{$terminate}">
                    <xsl:value-of select="concat($level, ':', $text)"/>
                </xsl:message>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Outline (Controlling Documents)

  1. Variables and Parameters [9]
    1. Variables [3]
    2. Parameters [5]
  2. Controlling Documents [6]
    1. Input Documents [3]
    2. Output Documents [2]
  3. Keys [6]
  4. Generating Result Nodes [2]
  5. Modularizing Stylesheets [2]
  6. Conclusions [1]

XSLT Processing Model

Outline (Input Documents)

  1. Variables and Parameters [9]
    1. Variables [3]
    2. Parameters [5]
  2. Controlling Documents [6]
    1. Input Documents [3]
    2. Output Documents [2]
  3. Keys [6]
  4. Generating Result Nodes [2]
  5. Modularizing Stylesheets [2]
  6. Conclusions [1]

Opening Documents

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:template match="/">
  <xsl:text>me: </xsl:text>
  <xsl:value-of select="count(document('document.xsl')/descendant::*)"/>
  <xsl:text>&#xa;http://dret.net/netdret/publications: </xsl:text>
  <xsl:value-of select="count(document('http://dret.net/netdret/publications')/descendant::*)"/>
 </xsl:template>
</xsl:stylesheet>

Whitespace in Documents

Controlling Whitespace

 <xsl:strip-space elements="*"/>
 <xsl:preserve-space elements="xsl:text"/>
 <xsl:template match="/">
  <xsl:text>xsl:text is used for outputting text.</xsl:text>
  <xsl:text> </xsl:text>
  <xsl:text>it also is the only element where whitespace nodes in the stylesheet are significant</xsl:text>
  <xsl:text>&#xa;</xsl:text>
  <xsl:value-of select="count(//text())"/>
 </xsl:template>

Outline (Output Documents)

  1. Variables and Parameters [9]
    1. Variables [3]
    2. Parameters [5]
  2. Controlling Documents [6]
    1. Input Documents [3]
    2. Output Documents [2]
  3. Keys [6]
  4. Generating Result Nodes [2]
  5. Modularizing Stylesheets [2]
  6. Conclusions [1]

Serialization

Multiple Output Documents

Outline (Keys)

  1. Variables and Parameters [9]
    1. Variables [3]
    2. Parameters [5]
  2. Controlling Documents [6]
    1. Input Documents [3]
    2. Output Documents [2]
  3. Keys [6]
  4. Generating Result Nodes [2]
  5. Modularizing Stylesheets [2]
  6. Conclusions [1]

Document Access

Declaring and Using Keys

XML and XSLT for using a Key

<people>
 <entry id="dret" country="de">
  <name>
   <pre>Erik</pre>
   <pre>Thomas</pre>
   <sur>Wilde</sur>
  </name>
  <email>dret@sims.berkeley.edu</email>
  <affiliation country="us">iSchool/UCB</affiliation>
  <phone location="office" type="voice">+1-510-6432253</phone>
  <phone location="office" type="fax">+1-510-6425814</phone>
 <xsl:key name="preNameKey" match="name" use="pre"/>
 <xsl:key name="affiliationKey" match="affiliation" use="."/>
 <xsl:key name="countryKey" match="entry | affiliation" use="@country"/>

XSLT Key Structure

preNameKey
Node Value
[1] Erik Thomas Wilde Erik
[1] Erik Thomas Wilde Thomas
[2] Thomas Plagemann Thomas
[3] Bob Glushko Bob
countryKey
Node Value
[1a] Erik Thomas Wilde de
[1b] iSchool/UCB us
[2a] Thomas Plagemann de
[2b] IFI/UIO no
[3a] Bob Glushko us
[3b] iSchool/UCB us

Using Keys

Node Set Intersection

$a[count(. | $b) = count($b)]: Find all nodes in $a where the cardinality of $b does not change when adding this node to it. This means the node must be in $b, and it is in $a to start with.

Outline (Generating Result Nodes)

  1. Variables and Parameters [9]
    1. Variables [3]
    2. Parameters [5]
  2. Controlling Documents [6]
    1. Input Documents [3]
    2. Output Documents [2]
  3. Keys [6]
  4. Generating Result Nodes [2]
  5. Modularizing Stylesheets [2]
  6. Conclusions [1]

Literal Result Elements

Producing Nodes Explicitly

 <xsl:template match="*">
  <xsl:element name="{translate(local-name(), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')}">
   <xsl:apply-templates select="node() | @*"/>
  </xsl:element>
 </xsl:template>
 <xsl:template match="@*">
  <xsl:attribute name="{translate(local-name(), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')}">
   <xsl:value-of select="."/>
  </xsl:attribute>
 </xsl:template>

Outline (Modularizing Stylesheets)

  1. Variables and Parameters [9]
    1. Variables [3]
    2. Parameters [5]
  2. Controlling Documents [6]
    1. Input Documents [3]
    2. Output Documents [2]
  3. Keys [6]
  4. Generating Result Nodes [2]
  5. Modularizing Stylesheets [2]
  6. Conclusions [1]

Including and Importing

Import Precedence

Outline (Conclusions)

  1. Variables and Parameters [9]
    1. Variables [3]
    2. Parameters [5]
  2. Controlling Documents [6]
    1. Input Documents [3]
    2. Output Documents [2]
  3. Keys [6]
  4. Generating Result Nodes [2]
  5. Modularizing Stylesheets [2]
  6. Conclusions [1]

XSLT in Practice