Extensible Style Language Transformations (XSLT)

What is XSL?

Tree operations within XSL

(Figure 6-1 Java and XML Book)

Using XSLT Style Sheets

XML Document (students.xml)

   <?xml version="1.0"?> 
   <course>
      <name id="csci_2962">Programming XML in Java</name>
      <teacher id="jp">John Punin</teacher>
      <student id="js">
         <name>John Smith</name>
         <hw1>30</hw1>
         <hw2>70</hw2>
         <project>80</project>
         <final>85</final>
      </student>
      <student id="gl">
         <name>George Lucas</name>
         <hw1>80</hw1>
         <hw2>90</hw2>
         <project>100</project>
         <final>40</final>
      </student>
      <student id="lr">
         <name>Elizabeth Roberts</name>
         <hw1>60</hw1>
         <hw2>95</hw2>
         <project>50</project>
         <final>90</final>
      </student>
   </course>

XSLT Style Sheet (students.xsl)

   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0" 
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="course">
         <HTML>
	 <HEAD>
	    <TITLE>Name of students</TITLE>
	 </HEAD>
	 <BODY>
            <xsl:apply-templates select="student"/>
	 </BODY>
         </HTML>
      </xsl:template>

      <xsl:template match="student">
         <P>
            <xsl:value-of select="name"/> 
         </P>
      </xsl:template>
   </xsl:stylesheet>

Making a Transformation Happen



XSLT Processors

Running Xalan Java Processor

java -classpath ":xalan.jar" org.apache.xalan.xslt.Process 
     -IN students.xml -XSL students.xsl -OUT students.html
Output File (students.html)
     <HTML>
     <HEAD>
     <TITLE>Name of students</TITLE>
     </HEAD>  
     <BODY>
     <P>John Smith</P>
     <P>George Lucas</P>
     <P>Elizabeth Roberts</P>
     </BODY>
     </HTML>

Creating XSLT Style Sheets

XSLT Style Sheets are well formed XML Documents

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

   </xsl:stylesheet>

Trivial XSL Style Sheet

   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0"
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="/">
          <HTML>
             <HEAD>
             <TITLE>
	        New XML Document
             </TITLE>
             </HEAD>
             <BODY>
	        Programming XML in Java
             </BODY>
          </HTML>
       </xsl:template>
   </xsl:stylesheet>

The xsl:apply-templates Element

     <?xml version="1.0"?> 
     <xsl:stylesheet version="1.0"
                     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
         <xsl:template match="/">
             <HTML>
             <HEAD>
                 <TITLE>Name of students</TITLE>
             </HEAD>
             <BODY>
                 <xsl:apply-templates/>
             </BODY>
             </HTML>
         </xsl:template>

         <xsl:template match="course">
             <xsl:apply-templates select="student"/>
         </xsl:template>

         <xsl:template match="student">
             <P>
	         Student Data
             </P>
         </xsl:template>
     </xsl:stylesheet>

The xsl:value-of to get the value of nodes


XSL Style Sheet:
   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0"
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="/">
         <HTML>
            <HEAD>
	       <TITLE>Name of students</TITLE>
	       </HEAD>
	       <BODY>
                  <xsl:apply-templates/>
	       </BODY>
            </HTML>
         </xsl:template>

         <xsl:template match="course">
            <xsl:apply-templates select="student"/>
         </xsl:template>

         <xsl:template match="student">
            <P>
               <xsl:value-of select="name"/> 
            </P>
         </xsl:template>
   </xsl:stylesheet>
HTML output file:
   <HTML>
   <HEAD>
   <TITLE>Name of students</TITLE>
   </HEAD>
   <BODY> 
   <P>John Smith</P>
   <P>George Lucas</P>
   <P>Elizabeth Roberts</P>
   </BODY>
   </HTML>

Handling multiple selections with xsl:for-each

   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0"
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
       <xsl:template match="/">
           <HTML>
	   <HEAD>
	      <TITLE>Name of students</TITLE>
	   </HEAD>
	   <BODY>
              <xsl:apply-templates/>
	   </BODY>
           </HTML>
       </xsl:template>

       <xsl:template match="course">
          <xsl:apply-templates select="student"/>
       </xsl:template>

       <xsl:template match="student">
          <xsl:for-each select="name">
             <P> <xsl:value-of select="."/> </P>
          </xsl:for-each>
       </xsl:template>
   </xsl:stylesheet>

Specifying Patterns for the match Attribute

Matching the root node:
   <xsl:template match="/">
    ...
   </xsl:template>
Matching elements:
   <xsl:template match="student">
    ...
   </xsl:template>
Matching children:
   <xsl:template match="course/student">
    ...
   </xsl:template>

   <xsl:template match="course/*/name">
    ...
   </xsl:template>
Matching Element descendants:
   <xsl:template match="course//name">
    ...
   </xsl:template>

Specifying Patterns for the match Attribute (2)

Example:

XSL Style Sheet
   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0" 
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="/">
         <HTML>
         <HEAD>
            <TITLE>Names</TITLE>
         </HEAD>
         <BODY>
            <xsl:apply-templates/>
         </BODY>
         </HTML>
      </xsl:template>

      <xsl:template match="text()">
      </xsl:template>

      <xsl:template match="course/name">
         <H2>
            <xsl:value-of select="."/> 
         </H2>
      </xsl:template>

      <xsl:template match="course/*/name">
         <H3>
            <xsl:value-of select="."/> 
         </H3>
      </xsl:template>
   </xsl:stylesheet>

HTML output file:
   <HTML>
   <HEAD>
   <TITLE>Names</TITLE>
   </HEAD>
   <BODY>
   <H2>Programming XML in Java</H2> 
   <H3>John Smith</H3>
   <H3>George Lucas</H3>
   <H3>Elizabeth Roberts</H3>
   </BODY>
   </HTML>

Specifying Patterns for the match Attribute (3)

Matching Attributes

Example:

XML Document Input (figures.xml)
   <?xml version="1.0"?> 
   <figures>
      <circle x="20" y="10" r="20"/>
      <rectangle x="-3" y="4" w="5" h="36"/>
      <ellipse x="-5" y="6" w="30" h="50"/>
      <rectangle x="7" y="23" w="58" h="45"/>
      <circle x="-2" y="5" r="35"/>
      <ellipse x="-10" y="-8" w="45" h="30"/>
   </figures>

XSL Style Sheet

   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0"
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="/">
         <HTML>
	    <HEAD><TITLE>Figures</TITLE></HEAD>
	    <BODY>
               <xsl:apply-templates/>
	    </BODY>
         </HTML>
      </xsl:template>

      <xsl:template match="figures">
         <TABLE>
	 <TR><TD>X</TD><TD>Y</TD></TR>
            <xsl:apply-templates select="circle"/>
         </TABLE>
      </xsl:template>

      <xsl:template match="circle">
         <TR><TD><xsl:value-of select="@x"/></TD>
	 <TD><xsl:value-of select="@y"/></TD></TR>
      </xsl:template>
   </xsl:stylesheet>

HTML output file:

   <HTML>
   <HEAD>
   <TITLE>Figures</TITLE>
   </HEAD>
   <BODY>
   <TABLE>
   <TR>
   <TD>X</TD><TD>Y</TD>
   </TR>
   <TR>
   <TD>20</TD><TD>10</TD>
   </TR>
   <TR>
   <TD>-2</TD><TD>5</TD>
   </TR>
   </TABLE>
   </BODY>
   </HTML>

Specifying Patterns for the match Attribute (4)

Matching Comments:
    <xsl:template match="comment()">
     ...
    </xsl:template>
Matching Text Nodes:
    <xsl:template match="text()">
     ...
    </xsl:template>

Specifying Patterns for the match Attribute (5)

Using the OR operator:

Example:   Generate list of name of students and project grades

XSL Style Sheet
   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="course">
         <HTML>
         <HEAD>
            <TITLE>Projects Grades</TITLE>
         </HEAD>
         <BODY>
         <TABLE>
            <xsl:apply-templates select="student"/>
         </TABLE>
         </BODY>
         </HTML>
      </xsl:template>

      <xsl:template match="text()">
      </xsl:template>

      <xsl:template match="student">
         <TR><xsl:apply-templates/></TR>
     </xsl:template>

     <xsl:template match="name | project"> 
        <TD><xsl:value-of select="."/></TD> 
     </xsl:template>
   </xsl:stylesheet>
HTML output file:
   <HTML>
   <HEAD>
   <TITLE>Projects Grades</TITLE>
   </HEAD>
   <BODY>
   <TABLE>
   <TR>
   <TD>John Smith</TD><TD>80</TD>
   </TR>
   <TR>
   <TD>George Lucas</TD><TD>100</TD>
   </TR>
   <TR>
   <TD>Elizabeth Roberts</TD><TD>50</TD>
   </TR>
   </TABLE>
   </BODY>
   </HTML>

Specifying Patterns for the match Attribute (6)

Testing with []

Example:   Name of the student with id 'js'

XSL Style Sheet:
   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0" 
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="course">
         <NAME>
            <xsl:apply-templates select="student"/>
         </NAME>
      </xsl:template>

      <xsl:template match="text()">
      </xsl:template>

      <xsl:template match="student[@id = 'js']">
         <xsl:value-of select="name"/> 
      </xsl:template>
   </xsl:stylesheet>

XPath

XPath axes

XPath Node tests

XPath Predicates

XPath Node Sets - XPath Predicates (2)

XPath Booleans - XPath Predicates (3)


Example:
    <xsl:template match="student[position() > 2]">
     ...
    </xsl:template>  

XPath Numbers - XPath Predicates (3)

XPath Strings - XPath Predicates (3)

XPath Examples

XPath Abbreviated Syntax

Expression

self::node()
parent::node()
child::childname
attribute::childname
/descendant-or-self::node()/
Abbreviation

.
..
childname
@childname
//

XPath Abbreviated Syntax Examples

Default XSLT Rules

1.    <xsl:template match="/ | *">
         <xsl:apply-templates/>
      </xsl:template>

2.    <xsl:template match="text()">
         <xsl:value-of select="."/>
      </xsl:template>

3.   <xsl:template match="@">
         <xsl:value-of select="."/>
      </xsl:template>

4.   <xsl:template match="comment()"/>
 
5.   <xsl:template match="processing-instruction()"/>

Style-sheet with no explicit rules:
   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0" 
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   </xsl:stylesheet>

Output File (applied to students.xml):
<?xml version="1.0" encoding="UTF-8"?>

  Programming XML in Java
  John Punin
  
    John Smith
    30
    70
    80
    85
  
  
    George Lucas
    80
    90
    100
    40
  
  
    Elizabeth Roberts
    60
    95
    50
    90

Creating Attribute Templates


XSL Style Sheet:
   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
       <xsl:template match="course">
          <STUDENTS>
             <xsl:apply-templates select="student"/>
          </STUDENTS>
       </xsl:template>

       <xsl:template match="student">
          <STUDENT NAME="{name}"
              HW1="{hw1}"
              HW2="{hw2}"
              PROJECT="{project}"
              FINAL="{final}"/> <xsl:text> 
          </xsl:text>
       </xsl:template>
   </xsl:stylesheet>
XML output file:
<?xml version="1.0" encoding="UTF-8"?>
<STUDENTS>
<STUDENT FINAL="85" PROJECT="80" HW2="70" HW1="30" NAME="John Smith"/>
<STUDENT FINAL="40" PROJECT="100" HW2="90" HW1="80" NAME="George Lucas"/> 
<STUDENT FINAL="90" PROJECT="50" HW2="95" HW1="60" NAME="Elizabeth Roberts"/> 
</STUDENTS>

Creating New Elements


For example, given this XML document (animals.xml):
   <?xml version="1.0"?> 
   <animals>
      <animal name="dog" class="mammal" legs="4"/>
      <animal name="shark" class="fish" legs="0"/>
      <animal name="chicken" class="bird" legs="2"/>
   </animals>
Transform it to this XML document (pets.xml):
   <?xml version="1.0" encoding="UTF-8"?>
   <pets>
      <mammal>
         <name>dog</name>
         <legs>4</legs>
      </mammal>
      <fish>
         <name>shark</name>
         <legs>0</legs>
      </fish>
      <bird>
         <name>chicken</name>
         <legs>2</legs>
      </bird>
   </pets>
We use this XSL Style Sheet:
   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0" 
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
       <xsl:output indent="yes"/>
       <xsl:template match="animals">
            <pets>
               <xsl:apply-templates select="animal"/>
            </pets>
       </xsl:template>

       <xsl:template match="animal">
            <xsl:element name="{@class}">
                 <name><xsl:value-of select="@name"/></name>
                 <legs><xsl:value-of select="@legs"/></legs>
            </xsl:element>
       </xsl:template>
   </xsl:stylesheet>

Creating New Attributes


For example, given this XML document (animals.xml):
   <?xml version="1.0"?> 
   <animals>
      <animal name="dog" class="mammal" legs="4"/>
      <animal name="shark" class="fish" legs="0"/>
      <animal name="chicken" class="bird" legs="2"/>
   </animals>
Transform it to this XML document (pets.xml):
   <?xml version="1.0" encoding="UTF-8"?>
   <pets>
      <mammal name="dog" legs="4"/>
      <fish name="shark" legs="0"/>
      <bird name="chicken" legs="2"/>
   </pets>
We use this XSL Style Sheet:
   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0"
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output indent="yes"/>
      <xsl:template match="animals">
         <pets>
            <xsl:apply-templates select="animal"/>
         </pets>
      </xsl:template>

      <xsl:template match="animal">
         <xsl:element name="{@class}">
            <xsl:attribute name="name">
               <xsl:value-of select="@name"/>
            </xsl:attribute>
            <xsl:attribute name="legs">
               <xsl:value-of select="@legs"/>
            </xsl:attribute>
         </xsl:element>
      </xsl:template>
   </xsl:stylesheet>

Copying and Sorting Nodes


For example: Sort the animal elements by leg number in (animals.xml)

XML Input file:
   <?xml version="1.0"?> 
   <animals>
      <animal name="dog" class="mammal" legs="4"/>
      <animal name="shark" class="fish" legs="0"/>
      <animal name="chicken" class="bird" legs="2"/>
   </animals>
XML Output file:
   <?xml version="1.0"?> 
   <animals>
      <animal name="shark" class="fish" legs="0"/>
      <animal name="chicken" class="bird" legs="2"/>
      <animal name="dog" class="mammal" legs="4"/>
   </animals>
XSL Style Sheet:
   <?xml version="1.0"?> 
   <xsl:stylesheet version="1.0" 
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output indent="yes"/>

      <xsl:template match="text()">
      </xsl:template>

      <xsl:template match="animals">
         <animals>
            <xsl:apply-templates>
               <xsl:sort data-type="number" select="@legs"/>
            </xsl:apply-templates>
         </animals>
      </xsl:template>

      <xsl:template match="animal">
         <xsl:copy>
            <xsl:apply-templates select="* | @*"/>
         </xsl:copy>
     </xsl:template>

     <xsl:template match="* | @*">
        <xsl:copy>
           <xsl:apply-templates select="* | @*"/>
        </xsl:copy>
     </xsl:template>
   </xsl:stylesheet>

Using xsl:variable and text output type

Problem:   Compute the average grade of each student and the total average of the course

XML Input file (students.xml):

XSL Style Sheet :
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>

  <xsl:template match="course">
    <xsl:apply-templates select="student"/>
    total average="<xsl:value-of select="(sum(//hw1) + 
                                          sum(//hw2) +
                                          sum(//final) +
                                          sum(//project))
                                          div (4*count(//student))"/>" 
  </xsl:template>

  <xsl:template match="student">
    <xsl:variable name="ave">
      <xsl:value-of select="(hw1 + hw2 + project + final) div 4"/>
    </xsl:variable>
    Student name="<xsl:value-of select="name"/>" 
    average="<xsl:value-of select="$ave"/>"
  </xsl:template>
</xsl:stylesheet>
Output file (grades.txt):
Student name="John Smith" 
        average="66.25"
Student name="George Lucas" 
        average="77.5"
Student name="Elizabeth Roberts" 
        average="73.75"
total average="72.5" 

Using xsl:if

Problem:   Print the name of the students and averages greater than 70

XML Input file (students.xml):

XSL Style Sheet:
<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="text"/>
   <xsl:template match="course">
      <xsl:apply-templates select="student"/>
   </xsl:template>

   <xsl:template match="student">
      <xsl:variable name="ave">
         <xsl:value-of select="(hw1 + hw2 + project + final) div 4"/>
      </xsl:variable>
      <xsl:if test="$ave > 70">
         Student name="<xsl:value-of select="name"/>" 
         average="<xsl:value-of select="$ave"/>"
      </xsl:if>
   </xsl:template>
</xsl:stylesheet>
Output file (grades70.txt):
Student name="George Lucas" 
        average="77.5"
      
Student name="Elizabeth Roberts" 
        average="73.75"

Controlling Output Type