practical xslt bob ducharme www snee com bob bob@snee com these slides www snee com xml 1 0 n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Practical XSLT Bob DuCharme snee/bob bob@snee these slides: snee/xml 1.0 PowerPoint Presentation
Download Presentation
Practical XSLT Bob DuCharme snee/bob bob@snee these slides: snee/xml 1.0

Loading in 2 Seconds...

play fullscreen
1 / 62

Practical XSLT Bob DuCharme snee/bob bob@snee these slides: snee/xml 1.0 - PowerPoint PPT Presentation


  • 125 Views
  • Uploaded on

Practical XSLT Bob DuCharme www.snee.com/bob bob@snee.com these slides: www.snee.com/xml 1.0. Outline. What is XSLT? Our first stylesheet: renaming and deletion Running stylesheets Reordering elements Renaming attributes Converting elements to attributes and vice versa

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

Practical XSLT Bob DuCharme snee/bob bob@snee these slides: snee/xml 1.0


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
practical xslt bob ducharme www snee com bob bob@snee com these slides www snee com xml 1 0
Practical XSLT

Bob DuCharme

www.snee.com/bob

bob@snee.com

these slides: www.snee.com/xml

1.0

outline
Outline

What is XSLT?

Our first stylesheet: renaming and deletion

Running stylesheets

Reordering elements

Renaming attributes

Converting elements to attributes and vice versa

Outputting plain text and controlling white space

Conditional execution

Selective output of data

XPath

slide4
XSLT

XSL Transformations (XSLT)

relationship to XSL

XSLT 1.0 W3C Recommendation November 16, 1999

XSLT 1.1 W3C Working Draft December 12, 2000

(as of 8 June 2005): XPath 2.0, XSLT 2.0, XQuery 1.0 in “last call Working Draft” status

from Abstract:

"This specification defines the syntax and semantics of XSLT, which is a language for transforming XML documents into other XML documents."

documents trees
Documents, trees

From section 1, "Introduction" of XSLT spec:

"A transformation expressed in XSLT describes rules for transforming a source tree into a result tree."

What about documents?

an xslt stylesheet
An XSLT stylesheet

<?xml version="1.0"?> 

<xsl:stylesheet version="1.0"

      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="year">

    <vintage>

      <xsl:apply-templates/>

    </vintage>

  </xsl:template>

  <xsl:template match="price">

  </xsl:template>

  <xsl:template match="@*|node()">

    <xsl:copy>

      <xsl:apply-templates select="@*|node()"/>

    </xsl:copy>

  </xsl:template>

</xsl:stylesheet>

"Literal result elements"

running it
Running it

my saxon shell script:

#! /bin/sh

java net.sf.saxon.Transform $1 $2 $3 $4 $5 $6 $7

saxon.bat:

java net.sf.saxon.Transform %1 %2 %3 %4 %5 %6 %7

Running example:

saxon -o wine1.out wine1.xml wine1.xsl

More processors: Xalan C++, Xalan Java, libxslt... see http://www.xmlsoftware.com/xslt.html.

effect of first example
Effect of first example

testxslt -in wine1.xml -xsl wine1.xsl

turns this

  <wine grape="chardonnay">

    <product>Carneros</product>

    <year>1997</year>

    <price>10.99</price>

  </wine>

into this:

  <?xml version="1.0" encoding="UTF-8"?>

  <wine grape="chardonnay">

    <product>Carneros</product>

    <vintage>1997</vintage>

  </wine>

empty xsl stylesheet element
Empty xsl:stylesheet element

<xsl:stylesheet version="1.0"

      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"/>

turns this

<winelist date="20000626">

  <wine grape="chardonnay">

     <product>Carneros</product>

    <year>1997</year>

     <price>10.99</price>

  </wine>

</winelist>

into this:

<?xml version="1.0" encoding="UTF-8"?>

    Carneros

     1997

    10.99

doing it yourself sample data
Doing it yourself: sample data

wine.xml for demonstrations

orders.xml for exercises

wine xml part 1 of 2
wine.xml (part 1 of 2)

<?xml version="1.0"?>

<winelist>

  <wine grape="chardonnay">

    <winery>Benziger</winery>

    <product>Carneros</product>

    <year>1997</year>

    <desc>Well-textured flavors, good finish.</desc>

    <prices>

      <list>10.99</list>

      <discounted>9.50</discounted>

      <case>114.00</case>

    </prices>

  </wine>

wine xml part 2 of 2
wine.xml (part 2 of 2)

  <wine grape="cabernet">

    <winery>Duckpond</winery>

    <product>Merit Selection</product>

    <year>1996</year>

    <desc>Sturdy and generous flavors, long finish.</desc>

    <prices>

      <list>13.99</list>

      <discounted>11.99</discounted>

      <case>143.50</case>

    </prices>

  </wine>

  <wine grape="chardonnay">

    <winery>Lindeman's</winery>

    <product>Bin 65</product>

    <year>1998</year>

    <desc>Youthful, with a cascade of spicy fig.</desc>

    <prices>

      <list>6.99</list>

      <discounted>5.99</discounted>

      <case>71.50</case>

    </prices>

  </wine>

</winelist>

orders xml part 1 of 5
orders.xml (part 1 of 5)

<!ELEMENT orders (order+)>        

<!ELEMENT order  (quantity, pricePerItem, orderDate,

warrantee?,billingAddr,shippingAddr?,productPic?)>

orders xml part 2 of 5
orders.xml (part 2 of 5)

<orders>

  <order orderNum="o43123" itemNum="i1009">

    <quantity>1</quantity>

    <pricePerItem>29.99</pricePerItem>

    <orderDate>20000623</orderDate>

    <warrantee>90 days parts and labor</warrantee>

    <billingAddr lastUpdate="20000623">

      <recip>Sterling Moss</recip>

      <line1>21 Manor Dr.</line1>

      <line2></line2>

      <city>Milford</city>

      <state>CT</state>

      <zip>06460</zip>

    </billingAddr>

    <productPic picent="a124"/>

  </order>

orders xml part 3 of 5
orders.xml (part 3 of 5)

  <order orderNum="o24987" itemNum="i0874">

    <quantity>4</quantity>

    <pricePerItem>9.99</pricePerItem>

    <orderDate>20000621</orderDate>

    <billingAddr lastUpdate="20000621">

      <recip>Johnny Herbert</recip>

      <line1>37 8th Ave.</line1>

      <line2>Apt. 3</line2>

      <city>Brooklyn</city>

      <state>NY</state>

      <zip>11217</zip>

    </billingAddr>

    <shippingAddr lastUpdate="19990405">

      <recip>Martin Blundell</recip>

      <line1>37 8th Ave.</line1>

      <line2>Apt. 5</line2>

      <city>Brooklyn</city>

      <state>NY</state>

      <zip>11217</zip>

    </shippingAddr>

    <productPic picent="a123"/>

  </order>

orders xml part 4 of 5
orders.xml (part 4 of 5)

  <order orderNum="o86734" itemNum="i2118">

    <quantity>1</quantity>

    <pricePerItem>300.00</pricePerItem>

    <orderDate>20000625</orderDate>

    <warrantee></warrantee>

    <billingAddr lastUpdate="19990422">

      <recip>Damon Hill</recip>

      <line1>321 Main St.</line1>

      <line2></line2>

      <city>Delavan</city>

      <state>WI</state>

      <zip>21353</zip>

    </billingAddr>

    <shippingAddr lastUpdate="19990405">

      <recip>Graham Hill</recip>

      <line1>9344 Simon Rd.</line1>

      <line2></line2>

      <city>Lake Geneva</city>

      <state>WI</state>

      <zip>21993</zip>

    </shippingAddr>

  </order>

orders xml part 5 of 5
orders.xml (part 5 of 5)

  <order orderNum="o67918" itemNum="i1009">

    <quantity>2</quantity>

    <pricePerItem>29.99</pricePerItem>

    <orderDate>20000622</orderDate>

    <warrantee></warrantee>

    <billingAddr lastUpdate="19981103">

      <recip>Jenson Button</recip>

      <line1>38 North Spring Ave.</line1>

      <line2>Apt. 32</line2>

      <city>Atlanta</city>

      <state>GA</state>

      <zip>92344</zip>

    </billingAddr>

    <productPic picent="a124"/>

  </order>

</orders>

exercise 1
Exercise 1

In a DOS window:

Enter "saxon" by itself to see what happens.

Take a look at empty.xsl and orders.xml with your text editor.

Have saxon process orders.xml using empty.xsl. You can pipe it to "more" or redirect it to a text file if you like.

Process the same XML file with identity.xsl.

reviewing renaming and deletion
Reviewing Renaming and Deletion

<?xml version="1.0"?> 

<xsl:stylesheet version="1.0"

      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="year">

    <vintage>

      <xsl:apply-templates/>

    </vintage>

  </xsl:template>

  <xsl:template match="price">

  </xsl:template>

  <xsl:template match="@*|node()">

    <xsl:copy>

      <xsl:apply-templates select="@*|node()"/>

    </xsl:copy>

  </xsl:template>

</xsl:stylesheet>

"Literal result elements"

deleting part 2
Deleting, Part 2

Another way to delete price from the following:

  <wine grape="chardonnay">

    <product>Carneros</product>

    <year>1997</year>

    <price>10.99</price>

  </wine>

is like this:

  <xsl:template match="wine">

    <wine>

      <!-- <xsl:apply-templates/> -->

      <xsl:apply-templates select="product"/>

      <xsl:apply-templates select="year"/>

    </wine>

  </xsl:template>

(Note how it also deletes the grape attribute.)

reordering elements
Reordering Elements

  <xsl:template match="wine">

    <wine grape="{@grape}">

      <xsl:apply-templates select="price"/>

      <xsl:apply-templates select="year"/>

      <xsl:apply-templates select="product"/>

    </wine>

  </xsl:template>

turns this

  <wine grape="chardonnay">

    <product>Carneros</product>

    <year>1997</year>

    <price>10.99</price>

  </wine>

into this:

  <wine grape="chardonnay">

    <price>10.99</price>

    <year>1997</year>

    <product>Carneros</product>

  </wine>

skeleton xsl
skeleton.xsl

<xsl:stylesheet version="1.0"

      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!--

<xsl:template match="">

  <xsl:apply-templates/>

</xsl:template>

-->

<xsl:template match="@*|node()">

  <xsl:copy>

    <xsl:apply-templates 

     select="@*|node()"/>

  </xsl:copy>

</xsl:template>

</xsl:stylesheet>

exercise 2
Exercise 2

Copy skeleton.xsl to create a stylesheet called ws1.xsl that does the following when orders.xml is used as input:

Renames quantity to amount and orderDate to dateOrdered

Deletes any warrantee and productPic elements (use either deletion method)

Moves the order date to be the first thing in the order and the shipping address to before the billing address

Don't worry about the order element's attributes for now.

renaming attributes
Renaming Attributes

  <wine grape="{@grape}">

outputs this:

  <wine grape="chardonnay">

And this

  <wine varietal="{@grape}">

will output this:

  <wine varietal="chardonnay">

converting attributes to elements vice versa
Converting Attributes to Elements & Vice Versa

  <xsl:template match="wine">

    <winevintage="{year}">

      <xsl:apply-templates select="product"/>

<category><xsl:value-of select="@grape"/>

      </category>

      <xsl:apply-templates select="price"/>

    </wine>

  </xsl:template>

converts

  <wine grape="chardonnay">

    <product>Carneros</product>

    <year>1997</year>

    <price>10.99</price>

  </wine>

to this:

  <wine vintage="1997">

    <product>Carneros</product>

    <category>chardonnay</category>

    <price>10.99</price>

  </wine>

attribute value templates
Attribute Value Templates

Following WRONG:

<wine functest =

      "<xsl:value-of select='string-length(@grape)'>">

Attribute value templates give you much of the power of xsl:value-of in attribute values.

Correct:

<wine functest="{string-length(@grape)}">

what we ve covered so far
What We've Covered So Far

deleting elements

renaming elements

reordering elements

deleting attributes

renaming attributes

converting elements to attributes

converting attributes to elements

exercise 3
Exercise 3

Prepare a stylesheet that copies orders.xml, doing the following to the result:

Rename the itemNum attribute to be just item.

Make orderNum a subelement of order instead of an attribute.

Make quantity an attribute of order instead of a subelement.

If time, give order a new child called addresses that has billingAddr and shippingAddr as its children. (Hint: you can use a literal result element with XSLT elements inside of it.)

controlling white space part 1
Controlling White Space, Part 1

<xsl:stylesheet version="1.0"

      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text"/>

  <xsl:template match="wine">

 test string 1

 <xsl:apply-templates select="winery"/>

 <xsl:text>test string 2</xsl:text>

 <xsl:apply-templates select="winery"/>

  </xsl:template>

</xsl:stylesheet>

controlling white space part 11
Controlling White Space, Part 1

Output of previous stylesheet with wine.xml:

  test string 1

  Benzigertest string 2Benziger

  test string 1

  Duckpondtest string 2Duckpond

  test string 1

  Lindeman'stest string 2Lindeman's

controlling white space part 2
Controlling White Space, Part 2

<xsl:stylesheet version="1.0"

      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text"/>

  <xsl:template match="wine">

    Wine:

    <xsl:apply-templates select="winery"/>

    <xsl:apply-templates select="product"/>

    <xsl:apply-templates select="year"/>

  </xsl:template>

</xsl:stylesheet>

controlling white space part 21
Controlling White Space, Part 2

Output of previous stylesheet with wine.xml:

Wine:

BenzigerCarneros1997

Wine:

DuckpondMerit Selection1996

Wine:

Lindeman'sBin 651998

controlling white space part 2b
Controlling White Space, Part 2b

<xsl:stylesheet version="1.0"

      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text"/>

  <xsl:template match="wine">

Wine:

<xsl:apply-templates select="winery"/><xsl:text>

</xsl:text>

    <xsl:apply-templates select="product"/><xsl:text>

</xsl:text>

    <xsl:apply-templates select="year"/>

  </xsl:template>

</xsl:stylesheet>

controlling white space part 2b1
Controlling White Space, Part 2b

Output of previous stylesheet with wine.xml:

Wine:

Benziger

Carneros

1997

Wine:

Duckpond

Merit Selection

1996

Wine:

Lindeman's

Bin 65

1998

exercise 4
Exercise 4

Prepare a stylesheet that creates a comma-separated value (CSV) from orders.xml showing each order's quantity, pricePerItem, and orderDate on each line.

The output should look like this:

1,29.99,20000623

4,9.99,20000621

1,300.00,20000625

2,29.99,20000622

Don't worry if lines are skipped between the lines of output, but make sure that each order's information is all on one line.

control structures if
Control Structures: if

<xsl:template match="wine">

  <wine grape="{@grape}">

<xsl:if test='@grape = "chardonnay"'>

      <emph>Special sale on chardonnays!</emph>

</xsl:if>

    <xsl:apply-templates select="*|@*|text()"/>

  </wine>

</xsl:template>

xsl if in action
xsl:if in Action

Prceding turns this:

<wine grape="chardonnay">

  <product>Carneros</product>

  <year>1997</year>

  <price>10.99</price>

</wine>

<wine grape="cabernet">

  <product>Merit Selection</product>

  <year>1996</year>

  <price>13.99</price>

</wine>

into this:

<wine grape="chardonnay">

<emph>Special sale on chardonnays!</emph>

  <product>Carneros</product>

  <year>1997</year>

  <price>10.99</price>

</wine>

<wine grape="cabernet">

  <product>Merit Selection</product>

  <year>1996</year>

  <price>13.99</price>

</wine>

control structures choose
Control Structures: choose

<xsl:template match="wine">

  <wine grape="{@grape}">

<xsl:choose>

<xsl:when test='@grape = "chardonnay"'>

        <emph>Special sale on chardonnays!</emph>

</xsl:when>

<xsl:when test='@grape = "cabernet"'>

        <emph>Gotta love them cabernets!</emph>

</xsl:when>

<xsl:otherwise>

        <emph>Another fabulous grape!</emph>

</xsl:otherwise>

</xsl:choose>

    <xsl:apply-templates select="*|@*|text()"/>

  </wine>

</xsl:template>

xsl choose in action
xsl:choose in Action

Preceding template turns this

<wine grape="chardonnay">

  <product>Carneros</product>

  <year>1997</year><price>10.99</price>

</wine>

<wine grape="cabernet">

  <product>Merit Selection</product>

  <year>1996</year><price>13.99</price>

</wine>

into this:

<wine grape="chardonnay">

<emph>Special sale on chardonnays!</emph>

  <product>Carneros</product>

  <year>1997</year><price>10.99</price>

</wine>

<wine grape="cabernet">

  <emph>Gotta love them cabernets!</emph>

  <product>Merit Selection</product>

  <year>1996</year><price>13.99</price>

</wine>

selective output based on data values part 1
Selective output based on data values, Part 1

<xsl:stylesheet version="1.0"

      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="wine">

<xsl:if test="@grape = 'chardonnay'">

   <xsl:copy>

      <xsl:apply-templates 

       select="@*|node()"/>

    </xsl:copy>

</xsl:if>

</xsl:template>

<xsl:template match="@*|node()">

  <xsl:copy>

    <xsl:apply-templates 

     select="@*|node()"/>

  </xsl:copy>

</xsl:template>

</xsl:stylesheet>

selective output based on data values part 11
Selective output based on data values, Part 1

<?xml version="1.0" encoding="utf-8"?><winelist>

  <wine grape="chardonnay">

    <winery>Benziger</winery>

    <product>Carneros</product>

    <year>1997</year>

    <desc>Well-textured flavors, good finish.</desc>

    <prices>

      <list>10.99</list>

      <discounted>9.50</discounted>

      <case>114.00</case>

    </prices>

  </wine>

  <wine grape="chardonnay">

    <winery>Lindeman's</winery>

    <product>Bin 65</product>

    <year>1998</year>

    <desc>Youthful, with a cascade of spicy fig.</desc>

    <prices>

      <list>6.99</list>

      <discounted>5.99</discounted>

      <case>71.50</case>

    </prices>

  </wine>

</winelist>

selective output based on data values part 2
Selective output based on data values, Part 2

<xsl:stylesheet version="1.0"

      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="wine[@grape != 'chardonnay']">

</xsl:template>

<xsl:template match="@*|node()">

  <xsl:copy>

    <xsl:apply-templates 

     select="@*|node()"/>

  </xsl:copy>

</xsl:template>

</xsl:stylesheet>

exercise 5
Exercise 5

Write a stylesheet that only copies the order elements with a pricePerItem of more than 50.

Remember that a < or > character inside of an attribute value must be represented as an entity reference (&lt; or &gt;).

xpath
XPath

Abstract of spec: a "language for addressing parts of an XML document, designed to be used by both XSLT and XPointer."

Split out from XSLT; became a W3C Recommendation in November of 1999.

Used by XSLT, XPointer, and by XQuery

iterating across a set of nodes
Iterating across a set of nodes

<a>

<b>3</b>

<c>10</c>

<b>4</b>

<c>20</c>

<b>5</b>

</a>

<xsl:stylesheet version="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="a">

<xsl:for-each select="b">

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

<xsl:text> </xsl:text>

</xsl:for-each>

</xsl:template>

</xsl:stylesheet>

output:

<?xml version="1.0" encoding="UTF-8"?>8 9 10

addressing parts of a document
Addressing Parts of a Document

<poem>

<title>Crossroad Blues</title>

<stanza>

<verse>I went down to the crossroads, fell down on my knees.</verse>

<verse>I went down to the crossroads, fell down on my knees.</verse>

<verse>Ask the lord above have mercy, save me if you please.</verse>

</stanza>

<stanza>

<verse>Standing at the crossroads, tried to flag a ride</verse>

<verse>Standing at the crossroads, tried to flag a ride</verse>

<verse>Nobody seems to know me, everybody pass me by.</verse>

</stanza>

</poem>

addressing parts of a document1
Addressing Parts of a Document

/poem/title

/poem/stanza/verse

/

/poem/*

..

../title

xpath syntax
XPath Syntax

XPath expression expressed as a location path.

Location path: one or more location steps separated by "/".

Slash at beginning makes it an absolute location path.

Compare Windows or Unix directory names: \windows\cookies vs. windows\cookies vs. ..\cookies, or /usr/bin vs. usr/bin vs. ../bin

For a winelist node, output the first year child of a wine element:

  <xsl:template match="winelist">

    <xsl:value-of select="wine/year"/>

  </xsl:template>

xpath location steps
XPath: Location Steps

From the XPath spec:

"A location step has three parts:

an axis, which specifies the tree relationship between the nodes selected by the location step and the context node,

a node test, which specifies the node type and expanded-name of the nodes selected by the location step, and

zero or more predicates, which use arbitrary expressions to further refine the set of nodes selected by the location step."

For XSLT purposes, the context node is the node that the XSLT processor is currently dealing with as it goes through the source tree's nodes.

xpath location steps axes
XPath Location Steps: Axes

axes: child, descendant, parent, ancestor, following-sibling, preceding-sibling, following, preceding, attribute, namespace, self, descendant-or-self, and ancestor-or-self.

child is default.

<xsl:value-of select="child::wine">

same as

<xsl:value-of select="wine">

preceding sibling axis and wine xml
preceding-sibling axis and wine.xml

<xsl:template match="product">

    <name>

      <xsl:value-of 

select="preceding-sibling::winery"/>

      <xsl:text> </xsl:text>

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

    </name>

  </xsl:template>

turns

 <winery>Benziger</winery>

 <product>Carneros</product>

into this:

<name>Benziger Carneros</name>

xpath location steps node test
XPath Location Steps: Node Test

<xsl:value-of select="child::wine">

<xsl:value-of select="wine">

Node test: "wine" above; "*" in following:

<xsl:value-of select="*">

xpath location steps predicate
XPath Location Steps: Predicate

From spec: "A predicate filters a node-set with respect to an axis to produce a new node-set."

<xsl:value-of select="child::wine[last()]"/>

<xsl:value-of select="child::wine[1]"/>

<xsl:value-of select="wine[@grape='cabernet']">

<xsl:value-of select="wine[count(*) = 0]">

<xsl:value-of select="wine[@grape]">

Contrast last one with

<xsl:value-of select="@grape">

xpath abbreviations part 1
XPath Abbreviations Part 1

Section 2.5, Abbreviated Syntax of the XPath spec lists handy abbreviations to use instead of the full axisname::nodeTest[predicate] syntax

. abbreviates self::node()

// abbreviates descendant-or-self::node() (node() returns true for all nodes)

Example: .//para is short for self::node()/descendant-or-self::node()/child::para, selecting all para descendants of the current node.

.. abbreviates parent::node()

xpath abbreviations part 2
XPath Abbreviations Part 2

@ abbreviates attribute::

Example: ../@grape selects the parent node's grape attribute; ../year selects context node's year sibling (compare UNIX and DOS relative path notation)

A missing axis abbreviates child::

Example: product abbreviates child::product

sample data for playing with axes
Sample Data for Playing with Axes

<!DOCTYPE thing [

<!ELEMENT thing (title,thing*)>

<!ATTLIST thing id ID #IMPLIED>

<!ELEMENT title (#PCDATA)>

]>

<thing id="i1"><title>main thing</title>

<thing id="i1-1"><title>child 1-1</title>

<thing id="i1-1-1"><title>child 1-1-1</title></thing>

<thing id="i1-1-2"><title>child 1-1-2</title>

<thing id="i1-1-2-1"><title>child 1-1-2-1</title> </thing>

<thing id="i1-1-2-2"><title>child 1-1-2-2</title> </thing>

</thing>

<thing id="i1-1-3"><title>child 1-1-3</title></thing>

</thing>

<thing id="i1-2"><title>child 1-2</title>

<thing id="i1-2-1"><title>child 1-2-1</title></thing>

<thing id="i1-2-2"><title>child 1-2-2</title></thing>

</thing>

</thing>

Thing n will have children thing n-1, thing n-2, etc.

xpath sample data tree structure
Xpath sample data: tree structure

i1

i1-2

i1-1

i1-2-1

i1-2-2

i1-1-1

i1-1-2

i1-1-3

i1-1-2-2

i1-1-2-1

following axis whole node list first node
"following" axis: Whole Node List, First Node

<xsl:stylesheet version="1.0"

      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="thing[@id = 'i1-1']">

    <xsl:for-each select="following::thing"> 

      <xsl:value-of  

select="attribute::id"/><xsl:text> </xsl:text> 

    </xsl:for-each>

  </xsl:template> 

  <xsl:template match="@*|*"> 

    <xsl:apply-templates select="@*|*"/> 

  </xsl:template> 

</xsl:stylesheet>

Output:

i1-2 i1-2-1 i1-2-2

select value of "following::thing[1]" would only select i1-2.

preceding axis whole node list first node
"preceding" axis: Whole Node List, "First" Node

<xsl:stylesheet version="1.0"

      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="thing[@id = 'i1-1-3']">

    <xsl:for-each select="preceding::thing"> 

      <xsl:value-of

select="attribute::id"/><xsl:text> </xsl:text> 

    </xsl:for-each>

  </xsl:template> 

  <xsl:template match="@*|*"> 

    <xsl:apply-templates select="@*|*"/> 

  </xsl:template> 

</xsl:stylesheet>

Output:

i1-1-1 i1-1-2 i1-1-2-1 i1-1-2-2

first preceding element
“first” preceding element

select value of "preceding::thing[1]" would select i1-1-2-2, noti1-1-1. Same with ancestor axis.

select value of "preceding::thing[last()] would select i1-1-1.

combining node sets with xpath expression
Combining Node Sets with XPath Expression

<xsl:template match="thing[@id = 'i1-1-2']"> 

  <xsl:for-each 

   select="preceding-sibling::thing | following-sibling::thing">

     <xsl:value-of select="attribute::id"/> 

     <xsl:text> </xsl:text> 

  </xsl:for-each>

</xsl:template>

Output:

i1-1-1 i1-1-3

exercise 6
Exercise 6

ws2.xsl lists all the nodes that are children of i1-1. Experiment with the context node and different axes in the xsl:for-each element's select value to see what gets selected. Try predicates of [last()] and [n] (where n is a number like 1 or 2), and try combining node sets with the OR (|) operator. (A comment in ws2.xsl shows the structure of the input and lists the axes.)

After exploring for a bit, find the XPath expression that selects every node in the document that starts before i1-1-3 . (Hint: note the "|" in the second template rule's match pattern in ws2.xsl.)

axes: child, descendant, parent, ancestor, following-sibling, preceding-sibling, following, preceding, attribute, namespace, self, descendant-or-self, and ancestor-or-self.