Lecture 4 XSLT
XSLT introduction Agenda Xpath Enhancing HTML Documents with XML Data Using XSLT and XPath to Transform XML Documents
XSLT introduction
XSLT (Extensible Stylesheet Language Transformations): Why XSLT? Why Do We Care? Maintaining the site the presentation layer of our site (the display aspects of the HTML) is embedded in and scattered throughout our Java code or C#. making changes to the look and feel of the site will be difficult engineers required to do cosmetic site work Accepting alternative product feeds our code currently depends on one particular DTD. What happens if it changes, or we want to accept product feeds from a different source with a different DTD? change our code / add new implementations translate their DTD to ours, and don’t change the code XML file needs transform from one to the other
XSLT : XSLT History Original concept: platform- and media-independent formatting language. Part I: Transformation Language intended for converting XML to a tree of formatting objects Part II: Formatting objects representing high-level typesetting constructs, such as <page>, <block> or <table>Original concept: platform- and media-independent formatting language. XSLT XSL XPath XSL(XML_FO)
XSLT : The need for XSL An XML document has no presentational information XSL adds layout and typesetting information to an XML document Not a new idea (e.g. Lotus 123 ver. 3: the “spreadsheet” and formatting information stored in separate files)
XSLT: Processing Model Middle Tier ActiveX XML File (.xml) XSL File (.xsl) Run MSXML or Xalan Display on IE or Netscape CSS File
XSL: Example – The XML File <NAME>Cheesecake with Fresh Fruit</NAME> <PRICE>4.00</PRICE> </ITEM> <ITEM> <NAME>Double Fudge Brownies</NAME> <PRICE>2.25</PRICE> </SECTION> <SECTION name="Beans"> <NAME>Columbian</NAME> <PRICE>8.99</PRICE> <NAME>Mexican Dark Roast</NAME> </MENU> <?xml version="1.0"?> <?xml:stylesheet type = "text/xsl" href = "menu.xsl"?> <MENU> <SECTION name="Coffee"> <ITEM> <NAME>Columbian</NAME> <PRICE>1.50</PRICE> </ITEM> <NAME>Cafe Latte</NAME> <PRICE>3.00</PRICE> <NAME>Americano</NAME> <PRICE>2.50</PRICE> </SECTION> <SECTION name="Dessert">
XSL: Example – The XSL Template <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <HTML><BODY> <TABLE border="2" bgcolor="yellow"> <TR><TH>Item</TH> <TH>Price</TH> </TR> <xsl:for-each select="MENU/SECTION/ITEM"> <TR><TD><xsl:value-of select="NAME"/></TD> <TD><xsl:value-of select="PRICE"/></TD> </xsl:for-each> </TABLE> </BODY></HTML> </xsl:template> </xsl:stylesheet> Menu1.xsl
Example – The Result Also can display it with IE If a JDK, Xalan and Xerces are installed on the machine, one could transform an XML file on the command line. % java org.apache.xalan.xslt.Process -in [input] –xsl [stylesheet] Class path must be set correctly Also can display it with IE
XSLT (Extensible Stylesheet Language Transformations) A declarative language for tree-to-tree translation (as opposed to Java and CSS, but like JSP) More general than just XML -> (X)HTML: a general translation from XML documents to any output document format also useful for XML to XML translations when you’re working with more than one DTD describing the same object General approach you provide an style sheet template that "looks like" the desired output document the template contains hooks into the source document so you can pull in content an XSLT processor parses an input document then builds an output tree based on the template in the style sheet
General template-driven tree transformation html dvd id= 3 price= 9 head body title actor character= ... title ul name Monsters Inc. Info for Monsters Inc. li li li li first last Title is Monster Inc. Price is 9 Billy ID is 3 Crystal Starring: Billy Crystal
XML to XML Transformation media product type=“dvd” merchant=AMZ id= 003 price= 900USD dvd id= 3 price= 9 title actor character= ... title artist type=actor name Monsters Inc. Monsters Inc. character name first last Billy Crystal Joe the Monster Billy Crystal Transformation template
XSL: Server-side XSL Processing Explicit invocation of the XSL processor (server side) monsters-inc.xml dvd.xml HTTP request for monsters-inc.html Server-side process (servlet): 1. retrieve the XML file 2. retrieve the XSL file 3. invoke the XSL translator 4. send back the HTML as HTTP response XSL translator
Client-side XSL Processing Browser has plug-in to process style sheets XML document declares its style sheet browser requests the style sheet and does the translation monsters-inc.xml HTTP round trip for monsters-inc.xml monsters-inc.xml Server-side process 1. serve the XML file 2. serve the XSL file dvd.xsl HTTP round trip for dvd.xsl dvd.xsl Browser w/ XSL translator HTTP request for monsters-inc.xml
What is XPath A declarative language for locating nodes and fragments in XML trees Used in both XPointer (for addressing), XSL (for pattern matching), XML Schema (for uniqueness and scope descriptions), and XQuery (for selection and iteration)
What is XPath? XPath is a syntax used for selecting parts of an XML document The way XPath describes paths to elements is similar to the way an operating system describes paths to files XPath is almost a small programming language; it has functions, tests, and expressions XPath is a W3C standard XPath is not itself written as XML, but is used heavily in XSLT XPath is used extensively in other specifications, e.g., XQuery, XSL, XPointer
Terminology library is the parent of book; book is the parent of the two chapters The two chapters are the children of book, and the section is the child of the second chapter The two chapters of the book are siblings (they have the same parent) library, book, and the second chapter are the ancestors of the section The two chapters, the section, and the two paragraphs are the descendents of the book <library> <book> <chapter> </chapter> <chapter> <section> <paragraph/> <paragraph/> </section> </chapter> </book> </library>
Operating system: XPath: Paths Operating system: XPath: / = the root directory /library = the root element (if named library ) /users/dave/foo = the (one) file named foo in dave in users /library/book/chapter/section = every section element in a chapter in every book in the library foo = the (one) file named foo in the current directory section = every section element that is a child of the current element . = the current directory . = the current element .. = parent of the current element .. = the parent directory /users/dave/* = all the files in /users/dave /library/book/chapter/* = all the elements in /library/book/chapter
Slashes A path that begins with a / represents an absolute path, starting from the top of the document Example: /email/message/header/from Note that even an absolute path can select more than one element A slash by itself means “the whole document” A path that does not begin with a / represents a path starting from the current element Example: header/from A path that begins with // can start from anywhere in the document Example: //header/from selects every element from that is a child of an element header This can be expensive, since it involves searching the entire document
Brackets and last() A number in brackets selects a particular matching child Example: /library/book[1] selects the first book of the library Example: //chapter/section[2] selects the second section of every chapter in the XML document Example: //book/chapter[1]/section[2] Only matching elements are counted; for example, if a book has both sections and exercises, the latter are ignored when counting sections The function last() in brackets selects the last matching child Example: /library/book/chapter[last()] You can even do simple arithmetic Example: /library/book/chapter[last()-1]
Stars A star, or asterisk, is a “wild card”—it means “all the elements at this level” Example: /library/book/chapter/* selects every child of every chapter of every book in the library Example: //book/* selects every child of every book (chapters, tableOfContents, index, etc.) Example: /*/*/*/paragraph selects every paragraph that has exactly three ancestors Example: //* selects every element in the entire document
Attributes I You can select attributes by themselves, or elements that have certain attributes Remember: an attribute consists of a name-value pair, for example in <chapter num="5">, the attribute is named num To choose the attribute itself, prefix the name with @ Example: @num will choose every attribute named num Example: //@* will choose every attribute, everywhere in the document To choose elements that have a given attribute, put the attribute name in square brackets Example: //chapter[@num] will select every chapter element (anywhere in the document) that has an attribute named num
Attributes II //chapter[@num] selects every chapter element with an attribute num //chapter[@num='3'] selects every chapter element with an attribute num with value 3 //chapter[not(@num)] selects every chapter element that does not have a num attribute //chapter[@*] selects every chapter element that has any attribute //chapter[not(@*)] selects every chapter element with no attributes
<?xml version="1.0" encoding="ISO-8859-1"?> <catalog> <cd country="UK"> <title>Dark Side of the Moon</title> <artist>Pink Floyd</artist> <price>10.90</price> </cd> <title>Space Oddity</title> <artist>David Bowie</artist> <price>9.90</price> <cd country="USA"> <title>Aretha: Lady Soul</title> <artist>Aretha Franklin</artist> </catalog> An XML document
country catalog.xml The XML document as a DOM tree catalog cd title artist price UK USA Dark Side of the Moon Space Oddity Aretha: Lady Soul Pink Floyd David Bowie Aretha Franklin 10.90 9.90
Getting the root element of the document catalog.xml catalog cd country title artist price UK USA Dark Side of the Moon Space Oddity Aretha: Lady Soul Pink Floyd David Bowie Aretha Franklin 10.90 9.90 catalog /catalog Getting the root element of the document
country country country catalog.xml catalog cd title artist price UK USA Dark Side of the Moon Space Oddity Aretha: Lady Soul Pink Floyd David Bowie Aretha Franklin 10.90 9.90 /catalog/cd cd cd country cd country country USA Finding child nodes
Finding descendant nodes catalog.xml /catalog/cd/price catalog cd country title artist price UK USA Dark Side of the Moon Space Oddity Aretha: Lady Soul Pink Floyd David Bowie Aretha Franklin 10.90 9.90 artist Finding descendant nodes
country country catalog.xml catalog cd title artist price UK USA Dark Side of the Moon Space Oddity Aretha: Lady Soul Pink Floyd David Bowie Aretha Franklin 10.90 9.90 /catalog/cd[price<10] cd cd country Condition on elements
// represents any directed path in the document catalog.xml /catalog//title catalog cd country title artist price UK USA Dark Side of the Moon Space Oddity Aretha: Lady Soul Pink Floyd David Bowie Aretha Franklin 10.90 9.90 //title country country title artist price title artist price // represents any directed path in the document
* represents any element name in the document catalog.xml catalog cd country title artist price UK USA Dark Side of the Moon Space Oddity Aretha: Lady Soul Pink Floyd David Bowie Aretha Franklin 10.90 9.90 /catalog/cd/* UK title artist price title artist price title artist price * represents any element name in the document
* represents any element name in the document /*/* catalog.xml What will the following expressions return? //* //*[price=9.90] catalog cd country title artist price UK USA Dark Side of the Moon Space Oddity Aretha: Lady Soul Pink Floyd David Bowie Aretha Franklin 10.90 9.90 * represents any element name in the document
Position based condition catalog.xml /catalog/cd[1] catalog cd country title artist price UK USA Dark Side of the Moon Space Oddity Aretha: Lady Soul Pink Floyd David Bowie Aretha Franklin 10.90 9.90 /catalog/cd[last()] Position based condition
country catalog.xml //title | //price catalog cd title artist price UK USA Dark Side of the Moon Space Oddity Aretha: Lady Soul Pink Floyd David Bowie Aretha Franklin 10.90 9.90 cd title artist price title artist price title artist price Use | for union
/catalog/cd[@country=“UK”] catalog.xml /catalog/cd[@country=“UK”] catalog cd country title artist price UK USA Dark Side of the Moon Space Oddity Aretha: Lady Soul Pink Floyd David Bowie Aretha Franklin 10.90 9.90 @ marks attributes
/catalog/cd/@country catalog.xml catalog cd country title artist price UK USA Dark Side of the Moon Space Oddity Aretha: Lady Soul Pink Floyd David Bowie Aretha Franklin 10.90 9.90 /catalog/cd/@country @ marks attributes
XPath Axes (plural of “axis”) We have discussed the following axes: Child (/) Descendant (//) Attribute (@) These symbols are actually a shorthand, e.g., /cd//price is the same as child::cd/descendant::price There are additional shorthands, e.g., Self (/.) Parent (/..)
Additional Axes ancestor Contains all ancestors (parent, grandparent, etc.) of the current node ancestor-or-self Contains the current node plus all its ancestors (parent, grandparent, etc.) descendant-or-self Contains the current node plus all its descendants (children, grandchildren, etc.) following Contains everything in the document after the closing tag of the current node following-sibling Contains all siblings after the current node preceding Contains everything in the document that is before the starting tag of the current node preceding-sibling Contains all siblings before the current node
Axes An axis (plural axes) is a set of nodes relative to a given node; X::Y means “choose Y from the X axis” self:: is the set of current nodes (not too useful) self::node() is the current node child:: is the default, so /child::X is the same as /X parent:: is the parent of the current node ancestor:: is all ancestors of the current node, up to and including the root descendant:: is all descendants of the current node (Note: never contains attribute or namespace nodes) preceding:: is everything before the current node in the entire XML document following:: is everything after the current node in the entire XML document
Axes (outline view) Starting from a given node, the self, preceding, following, ancestor, and descendant axes form a partition of all the nodes (if we ignore attribute and namespace nodes) <library> <book> <chapter/> <chapter> <section> <paragraph/> <paragraph/> </section> </chapter> <chapter/> </book> <book/> </library> //chapter[2]/self::* //chapter[2]/preceding::* //chapter[2]/following::* //chapter[2]/ancestor::* //chapter[2]/descendant::*
Axes (tree view) Starting from a given node, the self, ancestor, descendant , preceding, and following axes form a partition of all the nodes (if we ignore attribute and namespace nodes) ancestor paragraph[1] paragraph[2] section[1] chapter[2] chapter[1] chapter[3] book[1] book[2] library following preceding self descendant
Axis examples //book/descendant::* is all descendants of every book //book/descendant::section is all section descendants of every book //parent::* is every element that is a parent, i.e., is not a leaf //section/parent::* is every parent of a section element //parent::chapter is every chapter that is a parent, i.e., has children /library/book[3]/following::* is everything after the third book in the library
More axes ancestor-or-self:: ancestors plus the current node descendant-or-self:: descendants plus the current node attribute:: is all attributes of the current node namespace:: is all namespace nodes of the current node preceding:: is everything before the current node in the entire XML document following-sibling:: is all siblings after the current node Note: preceding-sibling:: and following-sibling:: do not apply to attribute nodes or namespace nodes
Abbreviations for axes (none) is the same as child:: @ is the same as attribute:: . is the same as self::node() .//X is the same as self::node()/descendant-or-self::node()/child::X .. is the same as parent::node() ../X is the same as parent::node()/child::X // is the same as /descendant-or-self::node()/ //X is the same as /descendant-or-self::node()/child::X
Arithmetic expressions + add - subtract * multiply div (not /) divide mod modulo (remainder)
Equality tests = means “equal to” (Notice it’s not ==) != means “not equal to” But it’s not that simple! value = node-set will be true if the node-set contains any node with a value that matches value value != node-set will be true if the node-set contains any node with a value that does not match value Hence, value = node-set and value != node-set may both be true at the same time!
Other boolean operators and (infix operator) or (infix operator) Example: count = 0 or count = 1 not() (function) The following are used for numerical comparisons only: < “less than” Some places may require < <= “less than Some places may require <= or equal to” > “greater than” Some places may require > >= “greater than Some places may require >= or equal to”
Some XPath functions XPath contains a number of functions on node sets, numbers, and strings; here are a few of them: count(elem) counts the number of selected elements Example: //chapter[count(section)=1] selects chapters with exactly two section children name() returns the name of the element Example: //*[name()='section'] is the same as //section starts-with(arg1, arg2) tests if arg1 starts with arg2 Example: //*[starts-with(name(), 'sec'] contains(arg1, arg2) tests if arg1 contains arg2 Example: //*[contains(name(), 'ect']
Using XSLT and XPath to Enhance HTML Documents
xalan/xt/saxon xalan: A free XSL processor, implemented in Java, from Apache (http://www.apache.org/) saxon: A free XSL processor, implemented in Java, from Michael Kay (http://users.iclway.co.uk/mhkay/saxon XML XSL xalan/saxon HTML (or XML or text)
Styling XML Documents using IE6 or Netscape7 Put a stylesheet PI (processing instruction) at the top of your XML document. Now you can simply drop the XML document into the browser and the XML will be automatically styled using the stylesheet referenced in the stylesheet PI. <?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> Add this stylesheet PI to the top of your XML document
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 (with embedded XSL elements) XSL Processor XSL element 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> Note how we have the HTML document embedded within an XSL template
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>
<?xml version=“1.0”?> Document / PI <?xml version=“1.0”?> Element FitnessCenter Element Member Element Name Element Phone Element Phone Element FavoriteColor Text Jeff Text 555-1234 Text 555-4321 Text lightgrey
Extract the FavoriteColor and use it 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>
Note 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>
Review - HTML Table <table border=“1” width=“100%”> <tr> </tr> <th> </th> <td> </td> 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> <td>Papaya</td> <td>Red</td> <td>Banana</td> <td>Yellow</td> </table> Fruit Color Papaya Red Banana Yellow
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.
<?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 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> </xsl:template> </xsl:stylesheet>
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)
<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 ... </xsl:if> 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>
Conditional Processing Use the <xsl:if test="…"/> element to perform conditional processing.
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.
<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 ... </xsl:if> 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>
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 Name Jeff Phone 555-1234 Phone 555-4321 Bottom line: we can access elements in other parts of the XML tree via the “../” operator.
Other ways to Access the XML Data Note: Assume that there are multiple Members <xsl:value-of select="/FitnessCenter/Member[1]/Name"/> "Select the Name of the first Member“ <xsl:value-of select="/FitnessCenter/Member[position()=1]/Name"/> <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>
Other ways to Access the XML Data (cont.) <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 select="/FitnessCenter//Name"> <!- - Process all Name elements which have FitnessCenter as an ancestor - ->
Other ways to Access the XML Data (cont.) <!- - Iterate through a list of Member nodes - -> <xsl:for-each select="/FitnessCenter/Member"> <!- - Output the Name of the "current" Member - -> <xsl:value-of select="./Name"/> </xsl:for-each> <!- - Since a specific Member is not specified, all Member nodes - -> <!- - all selected. That is, the Name node within each Member - -> <!-- node is selected. --> <xsl:for-each select="/FitnessCenter/Member/Name"> <xsl:value-of select="."/>
Nodelist This xPath expression: /FitnessCenter/Member selects a list of nodes (a list of Member nodes). This list of nodes is called a "nodelist".
Enhanced XML Document Note that each Member now has a unique id (the id attribute)
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)
Start Numbering from 0 How would you start the numbering from zero, rather than one? <xsl:number value="position() - 1" format="1">
format attribute of xsl:number In the previous example we saw how to generate numbers, and we saw that the generated numbers were 1, 2, 3, etc. With the format attribute we can specify the format of the generated number, i.e., 1, 2, 3 or I, II, III, or A, B, C, or … format=“1” generates the sequence: 1, 2, 3, … format=“01” generates: 01, 02, 03, … format=“A” generates: A, B, C, … format=“a” generates: a, b, c, … format=“I” generates: I, II, III, … format=“i” generates: i, ii, iii, ...
format attribute of xsl:number <xsl:for-each select="/FitnessCenter/Member"> <xsl:number value="position()" format="A"/> <xsl:text>. </xsl:text> <xsl:value-of select="Name"/> <BR/> </xsl:for-each> Output: A. Jeff B. David C. Roger
Sorting There is an XSL element that sorts the elements that you extract from the XML document <xsl:for-each select="/FitnessCenter/Member"> <xsl:sort select="Name" order="ascending"/> <xsl:value-of select="Name"/> <BR/> </xsl:for-each> Output: David Jeff Roger "For each Member, sort the Name elements"
Using XSLT and XPath to Transform XML Documents
Note All the xsl functionality that we learned in creating XSL-enhanced HTML documents are applicable in transforming XML documents
Transformation Language XSL may be used as a transformation language --> it may be used to transform an XML document into another XML document (perhaps the new one is the same, minus company sensitive data) XSL Transformation Engine (XSL Processor) XML XML
Example: Filter Gold 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 id="3" level="platinum"> <Name>Roger</Name> <Phone type="home">888-1234</Phone> <Phone type="work">888-4321</Phone> <FavoriteColor>lightyellow</FavoriteColor> </FitnessCenter> <?xml version="1.0"?> <gym> <Mem> <level> platinum</level> <XM>Jeff</XM> <home>555-1234</home> <work>555-4321</work> </Mem> </gym>
XML Transformations - all about (Template) “Rules” Each template rule has two parts: A pattern or matching part, that identifies the XML node in the source document to which the action part is to be applied. Matching information is contained in an attribute. An action part that details the transformation of the node
XSL Document Structure <?xml version=“1.0”?> <xsl:stylesheet> <xsl:template match=“/”> [action] </xsl:template> <xsl:template match=“FitnessCenter”> <xsl:template match=“Member”> ... </xsl:stylesheet>
xsl:element Suppose that you are writing a stylesheet to generate an XML document. Obviously, you will need your stylesheet to output elements. xsl:element is used to create elements <xsl:element name=“element-name”> [contents of the new element] </xsl:element> creates <element-name> [contents of the new element] </element-name>
Identity Transformation For our first example, lets create a stylesheet which simply creates an XML document that is a copy of the input XML document
<?xml version=“1.0”?> Document / PI <?xml version=“1.0”?> Element FitnessCenter Member Name Phone FavoriteColor ... Text Jeff 555-1234 555-4321 lightgrey
<xsl:output method="xml"/> <xsl:template match="/"> <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl=http://www.w3.org/1999/XSL/Transform version="1.0"> <xsl:output method="xml"/> <xsl:template match="/"> <xsl:apply-templates/> </xsl:template> <xsl:template match="FitnessCenter"> <xsl:element name="FitnessCenter"> </xsl:element> <xsl:template match="Member"> <xsl:element name="Member"> Cont. -->
<xsl:template match="Name"> <xsl:element name="Name"> <xsl:apply-templates/> </xsl:element> </xsl:template> <xsl:template match="Phone"> <xsl:element name="Phone"> <xsl:template match="FavoriteColor"> <xsl:element name="FavoriteColor"> <xsl:template match="text()"> <xsl:value-of select="."/> </xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?> <FitnessCenter> <Member> <Name>Jeff</Name> <Phone>555-1234</Phone> <Phone>555-4321</Phone> <FavoriteColor>lightgrey</FavoriteColor> </Member> <Name>David</Name> <Phone>383-1234</Phone> <Phone>383-4321</Phone> <FavoriteColor>lightblue</FavoriteColor> <Name>Roger</Name> <Phone>888-1234</Phone> <Phone>888-4321</Phone> <FavoriteColor>lightyellow</FavoriteColor> </FitnessCenter> Note that we've lost the attribute on the Member element
<xsl:template match="Member"> <xsl:element name="Member"> For each attribute Add an attribute to the element being output. The name of the attribute is the name of the current attribute being processed. The value of the attribute is the value of the current attribute being processed. Getting Member’s Attribute: <xsl:template match="Member"> <xsl:element name="Member"> <xsl:for-each select="@*"> <xsl:attribute name="{name(.)}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:for-each> <xsl:apply-templates/> </xsl:element> </xsl:template>
<?xml version="1.0" encoding="UTF-8"?> <FitnessCenter> <Member level=“platinum”> <Name>Jeff</Name> <Phone type="home">555-1234</Phone> <Phone type="work">555-4321</Phone> <FavoriteColor>lightgrey</FavoriteColor> </Member> <Member level=“gold”> <Name>David</Name> <Phone type="home">383-1234</Phone> <Phone type="work">383-4321</Phone> <FavoriteColor>lightblue</FavoriteColor> <Name>Roger</Name> <Phone type="home">888-1234</Phone> <Phone type="work">888-4321</Phone> <FavoriteColor>lightyellow</FavoriteColor> </FitnessCenter>
Generalize Our identity stylesheet will only work for FitnessCenter XML documents. We can make a stylesheet which does an identity transformation on any XML document.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl=http://www.w3.org/1999/XSL/Transform version="1.0"> <xsl:output method="xml"/> <xsl:template match="/"><xsl:apply-templates/> </xsl:template> <xsl:template match="*"> <xsl:element name="{name(.)}"> <xsl:for-each select="@*"> <xsl:attribute name="{name(.)}"><xsl:value-of select="."/></xsl:attribute> </xsl:for-each> <xsl:apply-templates/> </xsl:element> </xsl:template> <xsl:template match="text()"><xsl:value-of select="."/></xsl:template> </xsl:stylesheet>
Default Template Rules Every xsl document has two default template rules These rules are applied when the XSL Processor cannot find a template rule to use in your stylesheet Here are the two default template rules: “Match on the document or any element. The action is to go to the children and execute their template rules.” <xsl:template match=“/ | *”> <xsl:apply-templates/> </xsl:template> <xsl:template match=“text()”> <xsl:value-of select=“.”/> “Match on a text node. The action is to output the value of the text node.”
Multiple Applicable Rules Suppose that the XSL Processor is processing FitnessCenter and it gets to the <Member> element. Why does it use: <xsl:template match=“Member”>... and not the default template rule: <xsl:template match=“/ | *”>... ??? After all, both apply. Answer: given two rules that apply, the more specific rule wins. --> Clearly, “*” is much more general than “Member”. “*” matches on any element. “Member” just matches on the Member element.
Smallest Identity Transformation Stylesheet Now that we know about the default template rules, we can further reduce the size of the stylesheet.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="*"> <xsl:element name="{name(.)}"> <xsl:for-each select="@*"> <xsl:attribute name="{name(.)}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:for-each> <xsl:apply-templates/> </xsl:element> </xsl:template> </xsl:stylesheet>
<xsl:apply-templates select=“pattern”> The xsl:apply-templates element (without the select attribute) tells the XSL Processor to apply the template rules to all children (in document order) The xsl: apply-templates element can have a select attribute that tells the XSL Processor to process only the child element that matches “pattern”. Thus, the select attribute rule enables us to specify the order in which the children are processed
<xsl:apply-templates select=“pattern”> <xsl:template match="Member"> <xsl:apply-templates select="Name"/> <xsl:apply-templates select="Phone[@type='work']"/> </xsl:template> "Go to the template rule for my Name child element. Then go to the template rule for the work Phone child element." <xsl:template match="Member"> <xsl:apply-templates select="*"/> </xsl:template> "Go to all the child element nodes (not to any child text nodes)."
More Methods <xsl:template match=“FitnessCenter”> <xsl:element name=“{name(.)}”> <xsl:apply-templates/> </xsl:element> </xsl:template> <xsl:template match=“FitnessCenter”> <xsl:element name=“FitnessCenter”> <xsl:apply-templates/> </xsl:element> </xsl:template> <xsl:template match=“FitnessCenter”> <FitnessCenter> <xsl:apply-templates/> </FitnessCenter> </xsl:template>
XSLT: XML with XSLT
Thank you!