1.55k likes | 1.72k Views
Using XSLT and XPath. Roger L. Costello (XML Technologies) With changes and additions by Thomas Krichel http://openlib.org/home/krichel. Roger’s Acknowledgement. I wish to thank David Jacobs for showing me a new way of looking at HTML and XSLT/XPath
E N D
Using XSLT and XPath Roger L. Costello (XML Technologies) With changes and additions by Thomas Krichel http://openlib.org/home/krichel
Roger’s Acknowledgement • I wish to thank David Jacobs for showing me a new way of looking at HTML and XSLT/XPath • Many of the examples that I use in this tutorial come straight from David's excellent paper, Rescuing XSLT from Niche Status (see http://www.xfront.com)
Thomas acknowledgement • Roger L. Costello • Mitre Corp.
XSL transforms XML • XSL may be used to generate either HTML, XML, or text XSL XSL Processor XML HTML (or XML or text)
Doing it using Internet Explorer • First, download the latest version of Internet Explorer (at this time it is 6.0) • Write an XSL stylesheet stylish.xsl • Write an XML file, and refer to the xsl stylesheet with a processing instruction <?xml-stylesheet type="text/xsl“ href="stylish.xsl"?> Note: this does not work with other browsers!
General stuff Part 0
XML tree • XSL has a model of XML as a tree. • XSL tree model is similar to the DOM model. • As the processor does its job it looks at elements of the input tree and transforms them to the output tree. • The processor only writes the file to the tree at the end. • End points in the tree are called “nodes”.
in the general section • we examine how XSL looks at an XML document. In fact it builds a tree. • and then we look at a very simple way to look at what the stylesheet does. After that we have Roger showing us the details.
Seven types of nodes • root node: contains all the elements in the document. Not to be confused with the document element of XML. • element node: contains an element • text node: contain an as-large-as-possible area of text. • attribute node: contains attribute name and value • comment node: contains a comment • processing instruction (p-i) node • namespace node: each element node has one namespace node for every namespace declaration
properties of nodes: name • This is empty for the root, text and comment nodes. • for elments and attribute node, it is the name as it appears in the xml file, expanded by namespace declarations. • for p-i nodes, it is the target • for a namespace node, it is the prefix
properties of nodes: string value • for text nodes: the text • for comment nodes: the text of the comment • for p-i nodes: the data part of the p-i. • for an attribute node: the value of the attribute • for a root node: the concatenation of all the string values of all element and text children. • for a namespace node: the URI of the namespace
properties of nodes: base URI • for all nodes: the URI of the XML source document where the node has been found • Only of interest for elements and p-i nodes • for the root node: the URI of the document • for attribute, text and comment nodes: the base URI of its parent node
properties of nodes: children • for element nodes: all the element nodes, text nodes, p-i nodes and comment nodes between its start and end tags. • for root nodes: all the element nodes, text nodes, p-i nodes and comment nodes that are not children of some other node.
parent node • for all nodes except root nodes: the parent of the node. • attribute nodes and namespace nodes have an element node as parent node, but are not considered to be its child.
property of nodes: attribute • element: one to many attributes that the element has • other nodes: empty Now we look at what XSL does
Different formats… • <xsl:output method="xml"> is the default • <xsl:output method="html> • <xsl:output method="text"> used for everything else. Final formatting may be up to formatting objects, anyway. • Your stylesheet processor may have more formats, but they will be vendor-specific.
templates set rules <xsl:template match="expression"> do some stuff <xsl:template> This is a rule that says, if you find a node that matches the expression expression, then go ahead and do some stuff. It is called a template. The fact that a rule is written down down does not imply that it is applied.
applying templates • <xsl:apply-templates/> says: apply all template rules on the current node and on all its child nodes.
Default, built-in rules for the nodes • root: <xsl:apply-templates> on all children • element: <xsl:apply-templates> to the current node and all its children • attribute: copy the value as text to the output • text: copy the text to the output • comment, p-i, namespace: do nothing
Generating HTML part I
HTML Generation • We will first use XSL to generate HTML documents • When generating HTML, XSL should be viewed as a tool to enhance HTML documents. • That is, the HTML documents may be enhanced by extracting data out of XML documents • XSL provides elements (tags) for extracting the XML data, thus allowing us to enhance HTML documents with data from an XML document
Enhancing HTML Documents with XML Data HTML Document (with embedded XSL elements) XML Document XSL element XSL Processor XML data XML data
Enhancing HTML Documents with the Following XML Data <?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="FitnessCenter.xsl"?> <FitnessCenter> <Member level="platinum"> <Name>Jeff</Name> <Phone type="home">555-1234</Phone> <Phone type="work">555-4321</Phone> <FavoriteColor>lightgrey</FavoriteColor> </Member> </FitnessCenter> FitnessCenter.xml
Embed HTML Document in an XSL Template <?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>Welcome</TITLE> </HEAD> <BODY> Welcome! </BODY> </HTML> </xsl:template> </xsl:stylesheet> FitnessCenter.xsl (see html-example01)
Note • The HTML is embedded within an XSL template, which is an XML document. The HTML must be well formed. • We are able to add XSL elements to the HTML, allowing us to extract data out of XML documents. • Let's customize the HTML welcome page by putting in the member's name. This is achieved by extracting the name from the XML document. We use an XSL element to do this.
Extracting the Member Name <?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>Welcome</TITLE> </HEAD> <BODY> Welcome <xsl:value-of select="/FitnessCenter/Member/Name"/>! </BODY> </HTML> </xsl:template> </xsl:stylesheet> (see html-example02)
Extracting a Value from & Navigating the XML Document • Extracting values: • use the <xsl:value-of select="…"/> XSL element • Navigating: • The slash ("/") indicates parent/child relationship • A slash at the beginning of the path indicates that it is an absolute path, starting from the top of the XML document /FitnessCenter/Member/Name "Start from the top of the XML document, go to the FitnessCenter element, from there go to the Member element, and from there go to the Name element."
Document / PI <?xml version=“1.0”?> Element FitnessCenter Element Member Element Phone Element Name Element FavoriteColor Element Phone Text 555-4321 Text Jeff Text lightgrey Text 555-1234
Use FavoriteColor as the bgcolor <?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>Welcome</TITLE> </HEAD> <BODY bgcolor="{/FitnessCenter/Member/FavoriteColor}"> Welcome <xsl:value-of select="/FitnessCenter/Member/Name"/>! </BODY> </HTML> </xsl:template> </xsl:stylesheet> (see html-example03)
Using an extracted value as attribute Attribute values cannot contain "<" nor ">" - Consequently, the following is NOT valid: <Body bgcolor="<xsl:value-of select='/FitnessCenter/Member/FavoriteColor'/>"> To extract the value of an XML element and use it as an attribute value you must use curly braces: <Body bgcolor="{/FitnessCenter/Member/FavoriteColor}"> Evaluate the expression within the curly braces. Assign the value to the attribute.
Extract the Home Phone Number <?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>Welcome</TITLE> </HEAD> <BODY bgcolor="{/FitnessCenter/Member/FavoriteColor}"> Welcome <xsl:value-of select="/FitnessCenter/Member/Name"/>! <BR/> Your home phone number is: <xsl:value-of select="/FitnessCenter/Member/Phone[@type='home']"/> </BODY> </HTML> </xsl:template> </xsl:stylesheet> (see html-example04)
The predicate In this example we want "the Phone element where the value of its type attribute equals 'home' ": <xsl:value-of select="/FitnessCenter/Member/Phone[@type='home']"/> The expression within […] is called a "predicate". Its purpose is to filter. Note the use of the single quotes within the double quotes. select=" … ' …' …"
Review - HTML Table <table border=“1” width=“100%”> <th> </th> <th> </th> <th> </th> </tr> <tr> <td> </td> <td> </td> <td> </td> </tr> <tr> <td> </td> <td> </td> <td> </td> <tr> </tr> </table> This will create a table with 3 rows - the first row contains a header for each column. The next two rows contains the table data.
<table border=“1” width=“75%”> <tr> <th>Fruit</th> <th>Color</th> </tr> <tr> <td>Papaya</td> <td>Red</td> </tr> <tr> <td>Banana</td> <td>Yellow</td> </tr> </table> Fruit Color Red Papaya Yellow Banana
Create a Table of Phone Numbers • Suppose that a Member has an arbitrary number of phone numbers (home, work, cell, etc). • Create an HTML table comprised of the phone numbers. On each row of the table put the type (home, work, cell, etc) in one column and the actual phone number in the next column.
(leaving out xsl surroundings…) <HTML> <HEAD> <TITLE>Welcome</TITLE> </HEAD> <BODY bgcolor="{/FitnessCenter/Member/FavoriteColor}"> Welcome <xsl:value-of select="/FitnessCenter/Member/Name"/>! <BR/> Your phone numbers are: <TABLE border="1" width="25%"> <TR><TH>Type</TH><TH>Number</TH></TR> <xsl:for-each select="/FitnessCenter/Member/Phone"> <TR> <TD><xsl:value-of select="@type"/></TD> <TD><xsl:value-of select="."/></TD> </TR> </xsl:for-each> </TABLE> </BODY> </HTML> (see html-example05)
Iterating through XML Elements <xsl:for-each select="/FitnessCenter/Member/Phone"> <!- - Within here we are at one of the Phone elements. Thus, in <xsl:value-of select="path", the value for path is relative to where we are in the XML document. The "." refers to the Phone element that we are currently positioned at. - -> </xsl:for-each>
Absolute Path versus Relative Path <xsl:value-of select="/FitnessCenter/Member/Phone[@type='home']"/> This is an absolute xPath expression (we start from the top of the XML tree and navigate down the tree) <xsl:value-of select="@type"/> This is a relative xPath expression (relative to where we currently are located, give me the value of the type attribute) Do Lab1, Parts 1-3
Adding the name <HTML> <HEAD> <TITLE>Welcome</TITLE> </HEAD> <BODY bgcolor="{/FitnessCenter/Member/FavoriteColor}"> Welcome <xsl:value-of select="/FitnessCenter/Member/Name"/>! <BR/> Your phone numbers are: <TABLE border="1" width="25%"> <TR><TH>Name</TH><TH>Type</TH><TH>Number</TH></TR> <xsl:for-each select="/FitnessCenter/Member/Phone"> <TR> <TD><xsl:value-of select="../Name"/></TD> <TD><xsl:value-of select="@type"/></TD> <TD><xsl:value-of select="."/></TD> </TR> </xsl:for-each> </TABLE> </BODY> </HTML> (see html-example07)
Phone Name Phone 555-4321 555-1234 Jeff Getting the Name when accessing the Phone Member Notice how when in the for-each loop we need to access the Name which is "up and over" with respect to the Phone element Bottom line: we can access elements in other parts of the XML tree via the “../” operator.
Conditional Processing • Let's further enhance our example to provide a special offer to "platinum" members. • We need to check to see if the "level" attribute on the Member element equals "platinum". • Use the <xsl:if test="…"/> element to perform conditional processing. Do Lab1, Part 4
Adding the special offer, leaving phone numbers <HTML> <HEAD> <TITLE>Welcome</TITLE> </HEAD> <BODY bgcolor="{/FitnessCenter/Member/FavoriteColor}"> Welcome <xsl:value-of select="/FitnessCenter/Member/Name"/>! <BR/> <xsl:if test="/FitnessCenter/Member/@level='platinum'"> Our special offer to platinum members today is ... <BR/> </xsl:if> Your phone numbers are: </BODY> </HTML> (see html-example06)
Accessing Multiple Parts of the XML Document • Let's enhance the table to contain three columns - the name of the Member, the type of the phone (home, work, cell, etc), and the actual phone number. • Let us enlarge our document to contain a couple of more members.
<?xml version="1.0"?> <FitnessCenter> <Member id="1" level="platinum"> <Name>Jeff</Name> <Phone type="home">555-1234</Phone> <Phone type="work">555-4321</Phone> <FavoriteColor>lightgrey</FavoriteColor> </Member> <Member id="2" level="gold"> <Name>David</Name> <Phone type="home">383-1234</Phone> <Phone type="work">383-4321</Phone> <FavoriteColor>lightblue</FavoriteColor> </Member> <Member id="3" level="platinum"> <Name>Roger</Name> <Phone type="home">888-1234</Phone> <Phone type="work">888-4321</Phone> <FavoriteColor>lightyellow</FavoriteColor> </Member> </FitnessCenter>
Access repeated XML elements <xsl:value-of select="/FitnessCenter/Member[1]/Name"/> "Select the Name of the first Member" <xsl:value-of select="/FitnessCenter/Member[position()=1]/Name"/> "Select the Name of the first Member" <xsl:value-of select="/FitnessCenter/Member[last()]/Name"/> "Select the Name of the last Member" <xsl:for-each select="/FitnessCenter/Member[not(position()=last())]"> <!- - Process all Members but the last - -> </xsl:for-each>
Access repeated XML elements <xsl:for-each select="/FitnessCenter/Member[position() != last()]"> <!- - Process all Members but the last - -> </xsl:for-each> <xsl:for-each select="/FitnessCenter/Member[position() >1]"> <!- - Process all Members but the first - -> </xsl:for-each> <xsl:for-each select="/FitnessCenter//Name"> <!- - Process all Name elements which have FitnessCenter as an ancestor - -> </xsl:for-each>
Review - HTML Hyperlinking <A name="AnnaAndTheKing"></A> … <A href="#AnnaAndTheKing">Click Here</A> ... This creates an internal hyperlink (the source "anchor" links to the target anchor).
Hyperlink Name to Home Phone • Problem: create an HTML document that has two tables - a Member Name table, and a Member home Phone number table. • Hyperlink the Member's Name to his/her Phone.
<TABLE border="1" width="25%"> <TR><TH>Name</TH></TR> <xsl:for-each select="/FitnessCenter/Member"> <TR><TD> <A href="#{@id}"> <xsl:value-of select="Name"/> </A> </TD></TR> </xsl:for-each> </TABLE> <BR/><BR/><BR/><BR/><BR/> <TABLE border="1" width="25%"> <TR><TH>Home Phone Number</TH></TR> <xsl:for-each select="/FitnessCenter/Member"> <TR><TD> <A name="{@id}"> <xsl:value-of select="Phone[@type='home']"/> </A> </TD></TR> </xsl:for-each> </TABLE> Do Lab1, Parts 5-6
Numbering • There is an XSL element that returns a number corresponding to the element's position in the set of selected nodes <xsl:for-each select="/FitnessCenter/Member"> <xsl:number value="position()" format="1"/> <xsl:text>. </xsl:text> <xsl:value-of select="Name"/> <BR/> </xsl:for-each> Output: 1. Jeff 2. David 3. Roger (see html-example09)