JavaScript Editor Free JavaScript Editor     JavaScript Debugger 




Main Page

Previous Page
Next Page

10.3. Elements

Regardless of whether you consider XSLT to be a markup language, a scripting language, or just a pain in the fanny, it is, first and foremost, a dialect of XML and, therefore, must adhere to all of XML's rules. And I mean all of XML's rules because if it isn't well formed, then end of game. Fortunately, we've been there and done that already, which gives us the opportunity to look at the various XSLT elements available to us. Table 10-1 provides a high-level overview of these elementsnot quite an orbital overview, but close. Don't worry; we cover some of these elements in much greater detail shortly.

Table 10-1. XSLT Elements

Element

Attributes

Description

apply-imports

 

Applies external templates that have been imported using the import element.

apply-templates

select optional
mode optional

Applies templates that were defined locally.

attribute

name
namespace optional

Specifies an attribute for the preceding element.

attribute-set

name
use-attribute-sets
optional

Defines a named set of attributes that can be used to specify a list of attributes en mass instead of individually.

call-template

name

Used to invoke a named template.

choose

 

Indicates the beginning of a case structure.

comment

 

Used to create comments in the output document.

copy

use-attribute-sets
optional

Copies the current node and namespaces to the output document. However, it does not copy the children of the current node.

copy-of

select

Copies the node or nodes specified by the select attribute to the output document.

decimal-format

decimal-separator
optional
digit optional
grouping-separator
optional
infinity optional
minus-sign optional
name optional
NaN optional
pattern-separator
optional
per-mille optional
percent optional
zero-digit optional

Defines the appearance of numbers formatted using the format-number() function.

element

name
namespace
use-attribute-sets
optional

Used to create an element in the output document.

fallback

 

Specifies to the XSL processor alternative code to run in case an XSL element is not supported.

for-each

select

Loops through the node set specified by the select attribute.

if

test

Executes the enclosed XSL when the result of the test is TRue. It is important to remember that no else clause exists for the if element. In these instances, the choose, when, and otherwise elements should be used.

import

href

Imports an external style sheet, which is the same as including a style sheet.

include

href

Includes an external style sheet, which is the same as importing a style sheet.

key

name
match
use

Defines a search key that is used to locate specific nodes based upon their value or the value of another node.

message

terminate optional

Writes a programmer-defined message to the output document.

namespace-alias

stylesheet-prefix
result-prefix

Replaces the namespace specified with the stylesheet-prefix attribute on the input stylesheet with the namespace specified with the result-prefix attribute on the output document.

number

level optional
count optional
from optional
value optional
format optional
lang optional
letter-value optional
group-separator optional
grouping-size optional

Used to write a formatted number to the output document.

otherwise

 

Defines the default action for a case structure (choose).

output

method optional
version optional
encoding optional
omit-xml-declaration
optional
standalone optional
doctype-public optional
doctype-system optional
cdata-section-elements
optional
indent optional
media-type optional

Defines the format of the output document.

param

name
select optional

Used to specify template, stylesheet, and transform input parameters.

preserve-space

elements

Defines the elements for which whitespace is to be preserved on the output document.

processing-instruction

name

Writes an XML processing instruction to the output document.

sort

select optional
lang optional
data-type optional
order optional
case-order optional

Sorts a node set.

strip-space

elements

Defines the elements for which whitespace is not to be preserved on the output document.

stylesheet

id optional
extension-element-prefixes optional
exclude-result-prefixes optional
version

Defines the XSL document as a style sheet to the XSLT processor.

template

match optional
name optional
priority optional
mode optional

Defines a template, which is essentially an XSL function.

text

disable-output-escaping optional

Indicates that the enclosed is text.

transform

id optional
extension-element-prefixes optional
exclude-result-prefixes optional
version

Defines the XSL document as a style sheet to the XSLT processor, identical to the stylesheet element.

value-of

select
disable-output-escaping optional

Writes the information specified by the select attribute to the output document.

variable

name select optional

Defines either a local or global variable to the XSLT processor.

when

test

Defines the individual cases of a case structure (choose).

with-param

name select optional

Defines the parameters to a template.


10.3.1. In the Beginning

In the beginning, all your data was painted on the wall of a cave somewhere, and it was good. Depending on the available light, it was human readable, self-describing, colorful, and even pretty. Unfortunately, civilization has advanced to the point that cave paintings just can't express the sheer volume of information available to us today. Enter XML, which, like its distant ancestor, is also human readable, self-describing, and, if you're using an XML editor such as Stylus Studio, both colorful and pretty.

Although it might seem to some people that we've come full circle in our data storage, from cave paintings to XML, there is a distinct advantage to XML. Unlike a cave painting, which pretty much just sits there on the wall looking about the same as it did 40,000 years ago, XML is a bit more portable. With the addition of XSLT, XML is also elastic and flexible. I'm sold on the concept, how about you? Good. The only issue remaining is how to start developing an XSL style sheet.

All XSL style sheets begin with one of two elements, either the stylesheet element or the TRansform element. They are interchangeable because both do exactly the same thing, although I recommend not using the transform element during months with r's. Wait, maybe that was oystersI have a tendency to confuse the two.

The next part of the style sheet is the output element, which essentially describes the format of the output. This is where you make the commitment of whether the output document will be XML, HTML, text, or, gasp, even XSLT. Not big on commitment? Not a problem. Just leave out the output element, and the output defaults to XML. Of course, come to think of it, that, too, is a form of commitment.

The next "standard" part of an XSL style sheet is the first template, the one that starts the whole ball rolling. However, before we get there, I should point out that between the first element and the first template is where some really useful elements go. Parameters from the outside world and global variables are just two examples. In fact, let's take a look at Table 10-2, which indicates where elements can be defined in a style sheet and what effect location can have on their behavior.

Table 10-2. XSL Style Sheet Elements and Where They Can Be Defined

Element

Defined Where

apply-imports

Either root or element level

apply-templates

Either root or element level

attribute

Element level

attribute-set

Root level

call-template

Element level

choose

Element level

comment

Either root or element level

copy

Element level

copy-of

Element level

decimal-format

Root level

element

Element level

fallback

Element level

if

Element level

import

Root level

include

Root level

key

Root level

message

Element level

namespace-alias

Root level

number

Root level

otherwise

Element level

output

Root level

preserve-space

Root level

processing-instruction

Root level

sort

Element level

strip-space

Root level

stylesheet

Root level

template

Root level

text

Element level

TRansform

Root level

value-of

Element level

variable

Element level

when

Element level

with-param

Element level


At last we've come to the first template of the style sheet. Unfortunately, it is kind of anticlimatic because 99 percent of all style sheets start with a template element that looks just like this:

<xsl:template match="/">

Boring, isn't it? Yes, you can make it more specific and have it look for a particular element that should be in the input document. I don't recommend it, though, because it will only cause problems someday when, for some reason, that specific element is not in the input document. Then comes the inevitable yelling, the finger pointing, and the peasants with pitchforks and torches again. Not a pretty picture.

10.3.2. Templates and How to Use Them

After the initial template, the one that establishes the current location as the root, what are some of the other ways to use templates?

Earlier I stated that templates could have names, although it wasn't required. In XSLT, these named templates fill pretty much the same niche that functions do in a language such as JavaScript or PHP. They can accept parameters and return results. In my opinion, if it looks like a duck and walks like a duck, the odds are, it is a duck. Unless it is a goose, but that is kind of like duckzilla, so it isn't a problem.

Let's take a look at what a typical, although useless, named function looks like. Shown in Listing 10-6, its purpose is to accept two numbers, add them, and return the result.

Listing 10-6. Named Template

<xsl:template name="add">
      <xsl:param name="a" />
      <xsl:param name="b" />

      <xsl:value-of select="number($a) + number($b)" />
</xsl:template>

Thankfully, this is one of those times when something both seems simple and actually is simple, as long as you remember that dollar signs aren't required at definition but are required when used. However, the same thing can't always be said for templates invoked using XPathbut before we go there, perhaps it would be better to take a look at two more mundane templates. Using the XML shown way back in Listing 10-4, the style sheets shown in Listings 10-7 and 10-8 do exactly the same thing in a slightly different manner.

Listing 10-7. A Pure XSLT Example

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:preserve-space elements="text"/>

      <xsl:template match="/">

        <xsl:element name="div">
          <xsl:apply-templates select="//library"/>
        </xsl:element>

      </xsl:template>

      <xsl:template match="library">

        <xsl:element name="table">
          <xsl:attribute name="width">100%</xsl:attribute>

          <xsl:for-each select="book">
            <xsl:element name="tr">

              <xsl:for-each select="*">
              <xsl:element name="td">
                <xsl:attribute name="width">33%</xsl:attribute>

                <xsl:value-of select="."/>

             <xsl:if test="string-length(.) = 0">
                  <xsl:text> </xsl:text>
                </xsl:if>
              </xsl:element>
            </xsl:for-each>
       </xsl:element>
        </xsl:for-each>
       </xsl:element>

     </xsl:template>

</xsl:stylesheet>

Listing 10-8. An XSLT/XHTML Hybrid Example

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:preserve-space elements="text"/>

      <xsl:template match="/">

        <xsl:element name="div">
          <xsl:apply-templates select="//library"/>
        </xsl:element>

      </xsl:template>

      <xsl:template match="library">

        <xsl:element name="table">
          <xsl:attribute name="width">100%</xsl:attribute>

          <xsl:for-each select="book">
            <tr>
              <xsl:for-each select="*">
                <td width="33%">
                  <xsl:value-of select="."/>

                  <xsl:if test="string-length(.) = 0">
                    <xsl:text> </xsl:text>
                  </xsl:if>
                </td>
              </xsl:for-each>
           </tr>
         </xsl:for-each>
         </xsl:element>

       </xsl:template>

</xsl:stylesheet>

Confused? Don't be. Because XSLT and XHTML are both dialects of XML, there is absolutely nothing wrong with mixing the two. At first glance, the style sheet shown in Listing 10-8 might seem to be a little like a mutt, part this and part that. But as weird as it seems, it is much more common than the purebred solution from Listing 10-7.

Earlier I stated that templates invoked using XPath aren't always simple because, at times, more than one template matches. If you don't expect this, it could, at the very least, be an embarrassment. However, there is a way to specify which template to use when more than one matches the criteria.

The mode attribute, which is on both the template and apply-templates elements, is used to specify which template to use when a particular select could result in more than one match. Listing 10-9, a merging of Listings 10-7 and 10-8, has an example of this. The only difference, other than the merging, is the addition of a mode attribute for the mutt template and a new applytemplates element, also with a mode attribute.

Listing 10-9. Distinguishing Template Matches Using Mode

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:preserve-space elements="text"/>

  <xsl:template match="/">

    <xsl:element name="div">
      <xsl:apply-templates select="//library" />
      <xsl:apply-templates select="//library" mode="mutt" />
    </xsl:element>

  </xsl:template>

     <xsl:template match="library">

       <xsl:element name="table">
         <xsl:attribute name="width">100%</xsl:attribute>
         <xsl:for-each select="book">
           <xsl:element name="tr">

              <xsl:for-each select="*">
                <xsl:element name="td">
                  <xsl:attribute name="width">33%</xsl:attribute>

                  <xsl:value-of select="." />

              <xsl:if test="string-length(.) = 0">
                   <xsl:text> </xsl:text>
                 </xsl:if>
               </xsl:element>
             </xsl:for-each>
           </xsl:element>
         </xsl:for-each>
      </xsl:element>

    </xsl:template>

    <xsl:template match="library" mode="mutt">

      <xsl:element name="table">
        <xsl:attribute name="width">100%</xsl:attribute>

        <xsl:for-each select="book">
          <tr>
            <xsl:for-each select="*">
              <td width="33%">
                <xsl:value-of select="." />

                <xsl:if test="string-length(.) = 0">
                     <xsl:text> </xsl:text>
                   </xsl:if>
                 </td>
               </xsl:for-each>
          </tr>
        </xsl:for-each>
      </xsl:element>

        </xsl:template>

  </xsl:stylesheet>

The mode attribute provides additional criteria for the match. Instead of the XPath being the only criteria, the mode is also used. So a simple XPath match alone is not enough; there also has to be a match to the mode. This leads to some interesting possibilities, such as when the mode name is unknown. Just use an asterisk as the mode name and use the mode to indicate the depth, or something along those lines.

10.3.3. Decisions, Decisions

As in the majority of programming languages, XSLT provides flow control in the way of decision structures. Excluding apply-templates, which can be used for some similar functionality, there is the if element and a case structure, called choose. Basically, it is all easy stuff, but two issues with XSLT decisions can cause many developers problems.

The first of these issues is how to test for greater than and less than, and still keep the document well formed. Fortunately, the previous chapter covered this problem when discussing XPath. The only remaining issue is one that causes quite a number of headaches: a lack of an else for the if element.

Lack of an else might seem like, if not an insurmountable problem, at least an annoying problem. Because of this lack, the choose element is used more often in languages with an else. Listing 10-10 is an example of a workaround for this lack of an else statement.

Listing 10-10. A Workaround

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

  <xsl:template match="/">
    <xsl:variable name="value" select="7" />

    <xsl:element name="div">
      <xsl:choose>
        <xsl:when test="($value mod 2) = 0">Even</xsl:when>
        <xsl:otherwise>Not even</xsl:otherwise>
      </xsl:choose>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

10.3.4. Sorting Out Looping

XSL style sheets have a built-in mechanism for sorting node sets, which can be rather useful when information needs to be arranged in a specific sequence. As with everything in XSL, sorting is accomplished through the use of an element, which, appropriately, is called sort. Interesting how these things work out, isn't it?

Listings 10-11 and 10-12 both show examples of the use of the sort element, with a couple minor differences. For example, Listing 10-11 uses a for-each element to navigate through the node set, which is sorted into ascending sequence. In Listing 10-12, an apply-templates is used, and the node set is sorted into descending sequence.

Listing 10-11. A for-each Sort Example

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

  <xsl:template match="/">
    <xsl:element name="table">
      <xsl:attribute name="width">100%</xsl:attribute>

      <xsl:for-each select="//book">
           <xsl:sort select="title" order="ascending" />

           <xsl:element name="tr">
             <xsl:for-each select="*">
               <xsl:element name="td">
                 <xsl:value-of select="." />
               </xsl:element>
             </xsl:for-each>
           </xsl:element>
         </xsl:for-each>
    </xsl:element>

  </xsl:template>

</xsl:stylesheet>

Listing 10-12. A template sort Example

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

  <xsl:template match="/">
    <xsl:element name="table">
      <xsl:attribute name="width">100%</xsl:attribute>

      <xsl:apply-templates select="//book">
       <xsl:sort select="title" order="descending" />
        </xsl:apply-templates>
      </xsl:element>

  </xsl:template>

  <xsl:template match="*">

    <xsl:element name="tr">
      <xsl:for-each select="*">
        <xsl:element name="td">
        <xsl:value-of select="." />
      </xsl:element>
       </xsl:for-each>
     </xsl:element>

  </xsl:template>

</xsl:stylesheet>


Previous Page
Next Page

R7


JavaScript Editor Free JavaScript Editor     JavaScript Debugger


©