Introduction to XSLT

I've just moved hosting companies and not all functions work on this page yet.

This page is for people who know XML well, and would like a brief overview of what XSLT can do. View this page as series of slides

  1. Preview During this session we will explore the following topics:
    1. What is XSL?
    2. What is the syntax?
    3. How much power does it offer us?
    4. What is its realtionship to SQL?
  2. Introduction

    XSLT is an acronym of "Extensible Stylesheet Language Transformations". XSLT is easily confused with Cascading Style Sheets (CSS). CSS is concerned about presentation of data, while XSLT is used for creating new documents by rearranging and filtering xml data. XSLT can make multiple passes over a document.

  3. The Big Idea

    XSL Transformations convert an XML document to another format. In the process we do fun things like rearrange the elements, prune some data, and add text before and after elements.

    For example, Given an XML document like this:

    <fruits>
    <fruit name="apple" quantity="3" />
    <fruit name="pears" quantity="5" />
    </fruits>
    

    We can convert this information to an HTML table that looks like this:

    <html>
    <body>
    <h1>Fruit Inventory</h1>
    <table border="1">
    <tr><th>Name</th><th>Quantity</th></tr>
    <tr><td>apple</td><td>3</td></tr>
    <tr><td>pears</td><td>5</td></tr>
    </table>
    </body>
    </html>
    
    

    The following XSLT file tells us how to convert the XML to something else, in this case an HTML file. It may look like greek now, but we'll learn what it means soon.

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
    <html>
    <body>
    <h1>Fruit Inventory</h1>
    <table border="1">
    <tr><th>Name</th><th>Quantity</th></tr>
      <xsl:apply-templates select="*" />
    </table>
    </body>
    </html>
    </xsl:template>
    
    <!-- templates -->
      <xsl:template match="fruit">
    <tr><td> <xsl:value-of select="@name" /> </td><td> <xsl:value-of select="@quantity" /> </td></tr>
      </xsl:template>
    
    </xsl:stylesheet>
    
    

    How do we convert to the HTML table from the XML file and an XSLT style sheet? We can do this in a few different ways. One is in programs written in something like C#, which I'll show you later. An easier way is to let your browser do it for you by adding a style sheet reference. This works for most modern browsers.

    <?xml version='1.0' encoding='utf-8' ?>
    <?xml-stylesheet type="text/xsl" href="simpleExample.xslt"?>
    <fruits>
    <fruit name="apple" quantity="3" />
    <fruit name="pears" quantity="5" />
    </fruits>
    

    If you enter http://www.fincher.org/tips/web/xslt/simpleExample2.xml into a browser window it will load the above file and make the transformation for you.

  4. XPath

    From the w3.org definition: XPath is the result of an effort to provide a common syntax and semantics for functionality shared between XSL Transformations [XSLT] and XPointer [XPointer]. The primary purpose of XPath is to address parts of an XML [XML] document. In support of this primary purpose, it also provides basic facilities for manipulation of strings, numbers and booleans.

    The return value of an XPath expression may be a node set, string, integer, or boolean value.

    XPath typically operates on three types of nodes, Element nodes, attribute nodes, and text nodes.

  5. XPath "Location Paths"

    A "location step" selects a set of nodes relative to the context node and has the general format of

    axis::node-test[predicate]*
    
    Example:
    child::Country[@name='US']
    
    1. The "axis" is one of the following:

      Axis Abbreviation Description
      child (empty string) All the direct children (no grandchildren, attribute nodes, or namespaces)
      descendant // All the children (no attribute nodes or namespaces)
      parent .. the immediate parent
      ancestor all the nodes above this one until the root is reached
      following-sibling all siblings after current node
      preceding all sibling before this node
      following all the nodes after this one, but not its descendents
      preceding all the nodes before this one (no ancestors, attributes, or namespaces)
      attribute @ all the attribute nodes for this node
      namespace namespaces nodes of the context node
      self . the context node itself
      descendant-or-self all descendents and self
      ancestor-or-self all ancestors and self
    2. 'node-test' typically is the name of an element (e.g., employee, salary, city)

    3. 'predicate' is an XPath expression that (ultimately) evaluates to a boolean value or oddly enough to an integer (e.g., [position() = last()]

  6. XPath expressions
    1. Node Set Functions

      Examples: last(), position(), count()

    2. String Functions

      Examples: starts-with(), contains(), string-length(),

    3. Boolean Functions

      Examples: not, true, false

    4. Number Functions

      Examples: number(), sum(), floor(), ceiling(), round() ,or, and, =, != ,<=, <, >=, >, mod
      Note about boolean expressions. In xpath the literals "and" and "or" are used as conjunctions, not "&&" and "||".

  7. Location Path

    A "location path" consists of one or more location steps separated by "/". : Examples from w3.org:

    1. child::para selects the para element children of the context node

    2. child::* selects all element children of the context node

    3. child::text() selects all text node children of the context node

    4. child::node() selects all the children of the context node, whatever their node type

    5. attribute::name selects the name attribute of the context node

    6. attribute::* selects all the attributes of the context node

    7. descendant::para selects the para element descendants of the context node

    8. ancestor::div selects all div ancestors of the context node

    9. ancestor-or-self::div selects the div ancestors of the context node and, if the context node is a div element, the context node as well

    10. descendant-or-self::para selects the para element descendants of the context node and, if the context node is a para element, the context node as well

    11. self::para selects the context node if it is a para element, and otherwise selects nothing

    12. child::chapter/descendant::para selects the para element descendants of the chapter element children of the context node

    13. child::*/child::para selects all para grandchildren of the context node

    14. / selects the document root (which is always the parent of the document element)

    15. /descendant::para selects all the para elements in the same document as the context node

    16. /descendant::olist/child::item selects all the item elements that have an olist parent and that are in the same document as the context node

    17. child::para[position()=1] selects the first para child of the context node

    18. child::para[position()=last()] selects the last para child of the context node

    19. child::para[position()=last()-1] selects the last but one para child of the context node

    20. child::para[position()>1] selects all the para children of the context node other than the first para child of the context node

    21. following-sibling::chapter[position()=1] selects the next chapter sibling of the context node

    22. preceding-sibling::chapter[position()=1] selects the previous chapter sibling of the context node

    23. /descendant::figure[position()=42] selects the forty-second figure element in the document

    24. /child::doc/child::chapter[position()=5]/child::section[position()=2] selects the second section of the fifth chapter of the doc document element

    25. child::para[attribute::type="warning"] selects all para children of the context node that have a type attribute with value warning

    26. child::para[attribute::type='warning'][position()=5] selects the fifth para child of the context node that has a type attribute with value warning

    27. child::para[position()=5][attribute::type="warning"] selects the fifth para child of the context node if that child has a type attribute with value warning

    28. child::chapter[child::title='Introduction'] selects the chapter children of the context node that have one or more title children with string-value equal to Introduction

    29. child::chapter[child::title] selects the chapter children of the context node that have one or more title children

    30. child::*[self::chapter or self::appendix] selects the chapter and appendix children of the context node

    31. child::*[self::chapter or self::appendix][position()=last()] selects the last chapter or appendix child of the context node

  8. Templates

    Using XSLT is primary composed of writing "Templates" and then applying them. A template has the general form of:

    <xsl:template
      match = pattern
      name = qname
      priority = number
      mode = qname>
      <!-- Content: (xsl:param*, template) -->
    </xsl:template>
    
    Example:
      <xsl:template match="title">
         <br /> title <u><xsl:value-of select="." /></u>
      </xsl:template>
    
  9. Applying Templates

    Templates are then called (much like a function) by an "apply-templates" element.

    <xsl:apply-templates
      select = node-set-expression
      mode = qname>
      <!-- Content: (xsl:sort | xsl:with-param)* -->
    </xsl:apply-templates>
    
    Example:
    <xsl:apply-templates select="bookquotes/book/title" />
    
  10. Book Quote Examples:

    The following examples will all use the "bookquotes.xml" data file. This file contains a favorite quote from books I've read, along with information about the book.

    <bookquotes>
    
    <book isbn="0201835959" type="nonfiction" date="01/06/1975">
    <title>The Mythical Man-Month</title>
    <author>Fred Brooks</author>
    <quote> The programmer, like the poet, works only slightly removed from pure
    thought-stuff.  He builds his castles in the air, from air, creating
    by exertion of the imagination.</quote>
    <page>7</page>
    </book>
    
    <book isbn="0140260404" type="nonfiction" date="11/01/1996">
    <title>The Road Ahead</title>
    <author>Bill Gates</author>
    <quote>"Success is a lousy teacher."</quote>
    </book>
    
    <book isbn="068483068X" type="fiction" date="01/01/1936">
    <title>Gone with the Wind</title>
    <author>Margaret Mitchell</author>
    <quote>"Never pass up new experiences [Scarlett], They enrich the mind."  - Rhett Butler</quote>
    <quote>"Southerners can never resist a losing cause." - Rhett Butler</quote>
    <quote>"But, no matter what sights they [the defeated Southern aristocracy] had seen,
    what menial tasks they had done and would have to do, they remained ladies and
    gentlemen, royalty in exile..."</quote>
    </book>
    
    </bookquotes>
    
    
  11. A simple xsl file bookquotes1.xslt to create a simple list of the book titles

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template name='test' match="/">
    <!-- write the xhtml template -->
    <html>
    <head>
      <title>Book Quotes - Index of Titles</title>
      <link href="http://fincher.org/mystyle.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
    <h1>Book Quotes - Index of Titles</h1>
    
    <xsl:apply-templates select="bookquotes/book/title" /> <!-- this will search for templates -->
    </body>
    </html>
    </xsl:template>
    
    <!-- templates -->
      <xsl:template match="title">
      <!-- 'value-of select="."' will select the text between the xml tags for the current node -->
         <br /> title <u><xsl:value-of select="." /></u>
      </xsl:template>
    </xsl:stylesheet>
    
    

    Applying the above stylesheet to our xml datafile results in the following transformation.

  12. Using xsl:variables to avoid repeating data

    I hate to have the same text twice in a file, like in the title and h1 header, so lets use the xslt:variable element and only define it once, so it won't get out of sync.

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="title">Book Quotes - Index of Titles</xsl:variable>
    
    <xsl:template name='test' match="/">
    <html>
    <head>
      <title><xsl:value-of select="$title"/></title>
      <link href="http://fincher.org/mystyle.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
    <h1><xsl:value-of select="$title"/></h1>
    <xsl:apply-templates select="bookquotes/book/title" />
    </body>
    </html>
    </xsl:template>
    
    <!-- templates -->
      <xsl:template match="title">
         <br /> title: <u><xsl:value-of select="." /></u>
      </xsl:template>
    </xsl:stylesheet>
    
    

    Applying the above stylesheet we get this transformation.

  13. Print an attribute

    Lets write a small table and extract an attribute.

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="title">Book Quotes - Index of Titles</xsl:variable>
    
    <xsl:template name='test' match="/">
    <html>
    <head>
      <title><xsl:value-of select="$title"/></title>
      <link href="http://fincher.org/mystyle.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
    <h1><xsl:value-of select="$title"/></h1>
    <table border='1'>
    <tr><th>Title </th><th>ISBN </th></tr>
    
    <xsl:apply-templates select="bookquotes/book" />
    </table>
    </body>
    </html>
    </xsl:template>
    
    <!-- templates -->
    <xsl:template match="book">
       <tr>
           <td><xsl:value-of select="title" /></td>
     <!-- to get the value of an attribute, use the "@" character -->
           <td><xsl:value-of select="@isbn" /></td>
       </tr>
    </xsl:template>
    </xsl:stylesheet>
    
    

    Applying the above stylesheet we get this transformation.

  14. Using values as attribute values

    Use an attribute value inside another attribute. We use the a special syntax called 'Attribute Value Templates' to get the incoming attribute written to an outgoing attribute "{@isbn}"

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="title">Book Quotes - Index of Titles</xsl:variable>
    <xsl:template name='test' match="/">
    <html>
    <head>
      <title><xsl:value-of select="$title"/></title>
      <link href="http://fincher.org/mystyle.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
    <h1><xsl:value-of select="$title"/></h1>
    <table border='1'>
    <tr><th>Title </th><th>ISBN </th></tr>
    <xsl:apply-templates select="bookquotes/book" />
    </table>
    </body>
    </html>
    </xsl:template>
    <!-- templates -->
    <xsl:template match="book">
       <tr>
           <td><xsl:value-of select="title" /></td>
     <!-- to get the value of an attribute, use the "@" character -->
           <td>
              <a href="http://www.amazon.com/exec/obidos/ASIN/{@isbn}">See at Amazon</a>
           </td>
       </tr>
    </xsl:template>
    </xsl:stylesheet>
    
    

    Applying the above stylesheet we get this transformation.

    Note: This replaces the more verbose method of:

             <input type="checkbox" >
                 <xsl:attribute name="name">
                     <xsl:value-of select="@name"/>
                 </xsl:attribute>
             </input>
    
  15. Miscellanous expressions.

    XPath gives us many ways to query a DOM object and select only nodes that match certain criteria. Its functionality and SQL have some interesting overlaps.

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="title">Book Quotes - Index of Titles</xsl:variable>
    <xsl:template name='test' match="/">
    <html>
    <head>
      <title><xsl:value-of select="$title"/></title>
      <link href="http://fincher.org/mystyle.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
    <h1><xsl:value-of select="$title"/></h1>
    
    <br />The number of books in this file is 
           <xsl:value-of select="count(bookquotes/book)" />
    
    <br />Number of nonfiction books in this file is:
           <xsl:value-of select="count(bookquotes/book[@type='nonfiction'])" />
    <br />  **  Title(s) :
           <xsl:apply-templates select="/bookquotes/book[@type='nonfiction']/title" />
    
    
    <br />Number of books with more than one quote: 
           <xsl:value-of select="count(bookquotes/book[count(quote) > 1])" />
    <br />  **  Title(s) :
           <xsl:apply-templates select="/bookquotes/book[count(quote) > 1]/title" />
    <br />Number of books with only one quote:  
           <xsl:value-of select="count(bookquotes/book[count(quote) = 1])" />
    <br />  **  Title(s) :
           <xsl:apply-templates select="/bookquotes/book[count(quote) = 1]/title" />
     
    </body>
    </html>
    </xsl:template>
    
    <xsl:template match="title">
      <u><xsl:value-of select="." /></u> , 
    </xsl:template>
    
    
    
    </xsl:stylesheet>
    
    

    Applying the above stylesheet we get this transformation.

  16. Tiny stylesheet to print sorted attributes of the first element as a table
    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- style sheet to write the attributes of the first element as a table -->
    <xsl:template name='test' match="/">
    <!-- write xhtml body shell -->
    <html>
    <head>
      <title><xsl:value-of select="name(*)"/></title>
    </head>
    
    <body>
    <h1 style="text-align: center;"><xsl:value-of select="name(*)"/></h1>
        <xsl:apply-templates select="*/*" />
    </body>
    </html>
    </xsl:template>
    
    <!-- loop over attributes and write in html table -->
      <xsl:template match="*">
        <table border='1'>
         <tr><th>Attribute Name</th><th>Attribute Value</th></tr>
        <xsl:apply-templates select="attribute::*" >
           <xsl:sort select="name(.)"  order="descending" />
        </xsl:apply-templates>
        </table>
      </xsl:template>
    
      <xsl:template match="attribute::*" >
            <tr>
                <td> <xsl:value-of select="name(.)" /></td>
                <td><xsl:value-of select="." /></td>
            </tr>
      </xsl:template>
    
    </xsl:stylesheet>
    
    

    Applying the above stylesheet we get this transformation.

  17. Conditional Processing using xsl:if.

    We can place commas behind each attribute except the last one. This example also shows the use of the "xsl:for-each" element and the "xsl:text" element.

    <xsl:for-each select="Response">
    	 <xsl:value-of select="@name"/>
    	      <xsl:value-of select="@*"/>
              <xsl:if test="position() != last()">
    	           <xsl:text> ,</xsl:text> 
              </xsl:if> 
    </xsl:for-each>
    
    
  18. How to include html text from one file into another using xslt.

    This first file will include the second file, 'Footer.xslt' just above the closing body tag

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:include href="Footer.xsl" /> <!-- import the 'Footer.xsl' file -->
    <html>
    <body>
         <xsl:apply-templates select="Stuff" />
    ...
    ...
    <!-- now lets grab the contents of the Footer.xsl file -->
    <xsl:call-template name="footer"/>
    </body>
    </html>
    

    'Footer.xsl' should look like the following:

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template name="footer">
         <hr />Copyright 2002 Fincher Enterprises
      </xsl:template>
    </xsl:stylesheet>
    
    
  19. Using xsl:if to write default text, if no nodes found

    <xsl:template match="SurveyDescriptor[@status='active']">
      <tr>
        <td><xsl:value-of select="@name"/> </td>
        <td> 
            <xsl:if test="count(ScreenerQuestion) = 0"> 
             <!-- write "(None)" if no ScreenerQuestion children exist -->
             (None)
             </xsl:if>
          <xsl:for-each select="ScreenerQuestion">
             <xsl:value-of select="@name"/>
             (
    		  <xsl:for-each select="Response">
    			 <xsl:value-of select="@name"/>
    			   <xsl:value-of select="@*"/>
                  <xsl:if test="position() != last()">
    			      <xsl:text> ,</xsl:text> 
                  </xsl:if> 
    		  </xsl:for-each>
             )
          <br />
          </xsl:for-each>
        </td>
      </tr>
      </xsl:template>
    
      <xsl:if test='text() != "-- SelectOne --" and text() != "-- refuse --"'>
      ...
      </xsl:if>
    
    
  20. Sorting

    Elements in the tree can be easily sorted

         <xsl:apply-templates select="Surveys/Survey">
            <xsl:sort select="@priority" order="descending" data-type="number"/>
         </xsl:apply-templates>
    
  21. Formatting Numbers

    numbers can be operated on and formated for output. The following takes the 'total' attribute and divides it by the 'target' attribute. The '0%' multiplies by 100 and puts the '%' character behind it.

    <xsl:value-of select="format-number((@total div @target),'0%')"/>
    
  22. using the sum() function

    The nodeset returned by the expression is turned into numbers and then summed.

      <xsl:value-of select="sum(Surveys/Survey/cellName/@target) - sum(Surveys/Survey/cellName/@total)"/>
      <xsl:value-of select="sum(Surveys/Survey/cellName/@total)"/>
    
      <xsl:value-of select="sum(Surveys/Survey/cellName/@target)"/>
      <xsl:value-of select="format-number(sum(Surveys/Survey/cellName/@total) div sum(Surveys/Survey/cellName/@target), '0%')"/>
    
    
  23. To write characters with &s and other difficult characters

    Use the 'disable-output-escaping="yes"' attribute

    <xsl:text disable-output-escaping="yes"> &nbsp; </xsl:text>
    
  24. Bonus Example of Creating Slides

    This is the xsl for creating the "Slides" view of this information

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template name='test' match="/">
    <!-- write the xhtml template -->
    
    <html>
    <head>
    <title>KnowledgeBase/Web/XSLT</title>
    <link href="http://www.fincher.org/mystyle.css" rel="stylesheet" type="text/css" />
    <meta name="description" content="XSLT" />
    <meta name="keywords" content="XSLT" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
    </head>
    <body>
    <h1 style="text-align: center">XSLT Notes Page <xsl:value-of select="$page" /></h1>
    <hr />
    | <a href="http://fincher.org/cgi-bin/transform.sh?xmlfile=index.xml&xsltfile=generic.xslt&name=page&value={$page - 1}"> < Previous</a> |
        <xsl:apply-templates mode="i" select="ol/li" />
    <a href="http://fincher.org/cgi-bin/transform.sh?xmlfile=index.xml&xsltfile=generic.xslt&name=page&value={$page+1}">Next > </a> |
    <hr />
        <ol>
         <li value="{$page}">
         <xsl:apply-templates mode="x" select="ol/li[position() = $page]" />
         </li>
        </ol>
    <hr />
    | <a href="http://fincher.org/cgi-bin/transform.sh?xmlfile=index.xml&xsltfile=generic.xslt&name=page&value={$page - 1}"> < Previous</a> |
        <xsl:apply-templates mode="i" select="ol/li" />
    <a href="http://fincher.org/cgi-bin/transform.sh?xmlfile=index.xml&xsltfile=generic.xslt&name=page&value={$page+1}">Next > </a> |
    <hr />
    
    </body>
    </html>
    
    </xsl:template>
    
    <!-- templates -->
    <xsl:template mode="x" match="@*|node()" >
      <xsl:copy-of select="@*|node()" />
    </xsl:template>
    
    <xsl:template mode="i" match="ol/li" >
    
    <xsl:if test="position() != $page">
            <a href="http://fincher.org/cgi-bin/transform.sh?xmlfile=index.xml&xsltfile=generic.xslt&name=page&value={position()}" title="{text()}">
    <xsl:value-of select="position()" />
    </a> 
    </xsl:if>
    <xsl:if test="position() = $page">
    <b>
       <xsl:value-of select="position()" />
    </b>
    </xsl:if>
     |
    </xsl:template>
    
    </xsl:stylesheet>
    
    
  25. Get XML documents from SQL server

    SQL Server 2000 has a wacky format to retrieve XML documents. Below is an example:

    SELECT distinct 1     as Tag, 
       NULL as Parent,
       surveyName as [Survey!1!name],
       NULL as [cellName!2!name],
       NULL as [cellName!2!total],
       NULL as [cellName!2!target]
    FROM surveyDirectorQuotas 
    
    UNION ALL
    SELECT distinct 2 , 
       1,
       surveyName,
       cellName,
       total,
       target
    FROM surveyDirectorQuotas
    ORDER BY [Survey!1!name] , [cellName!2!name]
    FOR XML EXPLICIT
    

    This returns an XML document like the following:

    <Surveys>
      <Survey name="Beer">
        <cellName name="MatureEducatedMen" total="10" target="10" />
        <cellName name="MatureEducatedWomen" total="3" target="10" />
      </Survey>
      <Survey name="Cars">
        <cellName name="OtherEducatedMen" total="3" target="10" />
        <cellName name="OtherEducatedWomen" total="10" target="10" />
      </Survey>
      <Survey name="Grocery">
        <cellName name="EveryoneOver16" total="3" target="20" />
      </Survey>
      <Survey name="GroceryFull">
        <cellName name="EveryoneOver16" total="20" target="20" />
      </Survey>
    </Surveys>
    
    
  26. Command Line Transformations

    The NT command to do transformations with xalan

    java -classpath (directory)/xalan.jar org.apache.xalan.xslt.Process -IN bookquotes.xml -XSL bookquotes1.xslt -PARAM name value
    

    Microsoft provides a command line tool for xsl transformations called msxsl.exe

  27. Browser Based Transformations
    
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <?xml-stylesheet type="text/xsl" href="abook.xslt"?>
    <catalog>
    <keyword>Peter+Rabbit</keyword>
    <product_group>Books</product_group>
    
    <product>
       <ranking>1</ranking>
       <title>Beatrix Potter : The Complete Tales : The 23 Original Peter Rabbit Books & 4 Unpublished Works</title>
       <asin>0723244049</asin>
       <author>Potter, Beatrix</author>
       <image>http://images.amazon.com/images/P/0723244049.01.MZZZZZZZ.jpg</image>
       <release_date>19971000</release_date>
       <binding>Hardcover</binding>
       <availability> </availability>
       <tagged_url>http://www.amazon.com:80/exec/obidos/redirect?tag=phonelistscom&creative=9441&camp=1793&link_code=xml&path=ASIN/0723244049</tagged_url>
    </product>
    

    This works really well, if you know all the browsers hitting your site can do client side transformations.

  28. Server Side Transformation

    The link to your xslt transformed page can point to a cgi program that does the transformation on the server. Here's a bit of perl cgi code that invokes Xalan on an Apache server to transform for us.

        $xmlfile = $in{xmlfile};
        $xsltfile = $in{xsltfile};
        $name = $in{name};
        $value = $in{value};
         $cmd = "/usr/local/jdk/bin/java -classpath /big/dom/xfincher/www/xalan.jar org.apache.xalan.xslt.Process -IN ${xmlfile} -XSL ${xsltfile} -PARAM ${name} ${value}";
         open(RESULTSET, $cmd." | ") || die "cannot do a xslt transform";
         while($line = <RESULTSET>) {  
             chomp($line);  
             print "$line\n"; 
             }     
         close(RESULTSET);
    

    This is nice, but a heavy hit on the server cpu.

  29. Best of both worlds

    If the browser can transform, let it do it; otherwise do server-side transformation.

    <script>
    agt=navigator.userAgent.toLowerCase();
    IE6exist = agt.indexOf("msie 6.0");
    if (IE6exist > -1) {location = "abook.xml"}
    </script>
    
    <!--#include virtual="cgi-bin/books.sh?xmlfile=/big/dom/www/McGregorsGarden/abook.xml&xsltfile=/big/dom/www/McGregorsGarden/abook.xslt" -->
    
    

    See for yourself at www.McGregorsGarden.com

  30. Cocoon is a server side xsl transformer managed by the apache group.
  31. .Net transformation in c sharp

    You can reference csharp code from your .Net pages

    public class SurveyStatus : System.Web.UI.Page
    	{
    		private void Page_Load(object sender, System.EventArgs e)
    		{
             GetSurveyDescriptorXMLService service = new GetSurveyDescriptorXMLService();
             XmlDocument xmlDocument = service.GetAllSurveyDescriptorsAsXMLDoc();
    
             string output = Util.WriteXMLViaXSL(xmlDocument, "w:/SurveyDirector/data/Xsl/SurveyDescriptorStatus.xsl");
             
             Response.Write(output);
    		}
    	}
    

    This will reference this csharp code:

    public static string WriteXMLViaXSL(XmlDocument xmlDocument, string styleSheetFileName) {
             //read an xml doc, twist it with an xsl file and return as string
             XslTransform xslTransform = new XslTransform();
             xslTransform.Load(styleSheetFileName);
    
             return WriteXMLViaXSL(xmlDocument, xslTransform);
          }
     
    public static string WriteXMLViaXSL(XmlDocument xmlDocument, XslTransform xslTransform) {
             //read an xml doc, twist it with an xsl file and return as string
             StringWriter stringWriter = new StringWriter();
             XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);
             xmlTextWriter.Formatting = Formatting.Indented;
             xslTransform.Transform(xmlDocument, null, xmlTextWriter);
             xmlTextWriter.Flush();
    
             return stringWriter.ToString();
          }
    
  32. Addendum April 2004

    Example of using stylesheets for format an xml file into a friendly HTML page in IE6

    XSLT file:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" />
    <xsl:template match="/">
    <html>
    <title>Test Cases for 'BestPossibleSurvey' Calculations</title>
    <body>
    <h1 style='text-align: center'>Test Cases for 'BestPossibleSurvey' Calculations</h1>
    <table border='2'>
    <tr><th>Name</th><th>Description</th></tr>
         <xsl:apply-templates select="//BestPossibleSurvey" />
    </table>
    </body>
    </html>
    </xsl:template>
     
    <xsl:template match="BestPossibleSurvey">
    
    <tr>
    <td><xsl:value-of select="@name" /></td>
    <td><xsl:value-of select="@desc" /></td>
    </tr>
    </xsl:template>
     
    </xsl:stylesheet>
      
    

    XML file:

    <?xml version="1.0" encoding="utf-8" ?>
    <?xml-stylesheet type="text/xsl" href="BestPossibleSurvey.xslt"?>
    <Tests>
    <BestPossibleSurvey name="BPS01" 
          desc="The respondent has seen no keyquestions before."
          respondent="Respondents\\KQ01.xml"
          surveyStatus="SurveyStatus\\CASE02.xml"
          result="MOONMAND"
    />
    <BestPossibleSurvey name="BPS02a" 
          desc="The respondent checked yes to all keyquestions.  Same as BPS02 except the userID is changed, so the survey selection is also changed.  This tests to make sure that selections are random."
          respondent="Respondents\\BPS02a.xml"
          surveyStatus="SurveyStatus\\CASE02.xml"
          result="MOONMANF,MOONMANH,MOONMANJ,MOONMANI,MOONMANB,MOONMANA,MOONMANC,MOONMANE,MOONMAND"
    />
    <BestPossibleSurvey name="BPS03" 
          desc="The respondent checked yes to all keyquestions.  Same as BPS02a except the group's PriorityAlgorithm is changed to assigned, so the survey selection is also changed."
          respondent="Respondents\\BPS02a.xml"
          surveyStatus="SurveyStatus\\CASE02.xml"
          group="Tests\\Groups\\BPS03-Baseln.xml"
          result="MOONMANA"
    />
    </Tests> 
    
    
  33. Review During this session we will explore the following topics:
    1. What is XSL? - It transforms documents on browser or server.
    2. What is the syntax? Kinda wacky, but knowable.
    3. How much power does it offer us? A great amount of filtering and manupilating data.
    4. What is its realtionship to SQL? Similiar in function in many ways.
  34. My favorite links:
    1. Definition of www.w3.org/TR/xslt
    2. Definition of www.w3.org/TR/xpath
    3. www.xslt.com/
    4. www.topxml.com/xsl/
    5. http://www.devguru.com
  35. Recommended Books:
    Click to read reviews or buy Java and XSLT
    Click to read reviews or buy Beginning XSLT