Pattern Examples

Pattern Examples

The best way to understand patterns is by example. Suppose that you want to transform planets.xml into planets.html, but retain only the first planet, Mercury. You can do that with the predicate [position() < 2] , because the first planets position is 1, the next is 2, and so on. Note, however, that < is invariably a sensitive character for XSLT processors, because its what you use to start markup; rather than <, you should use &lt.; . And note that you have to strip the other elements out of planets.xml by supplying an empty template for them, which I can do with the predicate [position() >= 2] :

Listing 4.10 Retaining Only Mercury
 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">      <xsl:template match="/PLANETS">          <HTML>              <HEAD>                  <TITLE>                      The Planets Table                  </TITLE>              </HEAD>              <BODY>                  <H1>                      The Planets Table                  </H1>                  <TABLE BORDER="2">                      <TR>                          <TD>Name</TD>                          <TD>Mass</TD>                          <TD>Radius</TD>                          <TD>Day</TD>                      </TR>                      <xsl:apply-templates/>                  </TABLE>              </BODY>          </HTML>      </xsl:template>      <xsl:template match="PLANET[position() &lt.; 2]">         <TR>            <TD><xsl:value-of select="NAME"/></TD>            <TD><xsl:apply-templates select="MASS"/></TD>            <TD><xsl:apply-templates select="RADIUS"/></TD>            <TD><xsl:apply-templates select="DAY"/></TD>         </TR>     </xsl:template>      <xsl:template match="PLANET[position() >= 2]">     </xsl:template>  <xsl:template match="MASS">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>      </xsl:template>      <xsl:template match="RADIUS">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>      </xsl:template>      <xsl:template match="DAY">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>      </xsl:template>  </xsl:stylesheet> 

Heres the resulting documentnote that only the first planet, Mercury, was retained:

 <HTML>      <HEAD>          <TITLE>              The Planets Table          </TITLE>      </HEAD>      <BODY>          <H1>              The Planets Table          </H1>          <TABLE BORDER="2">              <TR>                  <TD>Name</TD>                  <TD>Mass</TD>                  <TD>Radius</TD>                  <TD>Day</TD>              </TR>              <TR>                  <TD>Mercury</TD>                  <TD>.0553 (Earth = 1)</TD>                  <TD>1516 miles</TD>                  <TD>58.65 days</TD>              </TR>           </TABLE>      </BODY>  </HTML> 

In the following example, COLOR and POPULATED attributes have been added to Earths <PLANET> element:

 <PLANET COLOR="blue" POPULATED="yes">      <NAME>Earth</NAME>      <MASS UNITS="(Earth = 1)">1</MASS>      <DAY UNITS="days">1</DAY>      <RADIUS UNITS="miles">2107</RADIUS>      <DENSITY UNITS="(Earth = 1)">1</DENSITY>      <DISTANCE UNITS="million miles">128.4</DISTANCE><!--At perihelion-->  </PLANET> 

How can you select only elements that have both COLOR and POPULATED attributes? You can use the predicate "[@COLOR and @POPULATED]" . To strip out the other elements so the default rules dont place their text into the result document, you can use a predicate such as "[not(@COLOR) or not(@POPULATED)]" , as shown in Listing 4.11.

Listing 4.11 Selecting Only Elements That Have Both COLOR and POPULATED Attributes
 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">      <xsl:template match="/PLANETS">          <HTML>              <HEAD>                  <TITLE>                      Colorful, Populated Planets                  </TITLE>              </HEAD>              <BODY>                  <H1>                      Colorful, Populated Planets                  </H1>                  <TABLE BORDER="2">                      <TR>                          <TD>Name</TD>                          <TD>Mass</TD>                          <TD>Radius</TD>                          <TD>Day</TD>                      </TR>                      <xsl:apply-templates/>                  </TABLE>              </BODY>          </HTML>      </xsl:template>      <xsl:template match="PLANET[@COLOR and @POPULATED]">         <TR>            <TD><xsl:value-of select="NAME"/></TD>            <TD><xsl:apply-templates select="MASS"/></TD>            <TD><xsl:apply-templates select="RADIUS"/></TD>            <TD><xsl:apply-templates select="DAY"/></TD>         </TR>      </xsl:template>      <xsl:template match="PLANET[not(@COLOR) or not(@POPULATED)]">      </xsl:template>      <xsl:template match="MASS">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>      </xsl:template>      <xsl:template match="RADIUS">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>      </xsl:template>      <xsl:template match="DAY">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>      </xsl:template>  </xsl:stylesheet> 

And heres the result:

 <HTML>      <HEAD>          <TITLE>              Colorful, Populated Planets          </TITLE>      </HEAD>      <BODY>          <H1>              Colorful, Populated Planets          </H1>          <TABLE BORDER="2">              <TR>                  <TD>Name</TD>                  <TD>Mass</TD>                  <TD>Radius</TD>                  <TD>Day</TD>              </TR>              <TR>                  <TD>Earth</TD>                  <TD>1 (Earth = 1)</TD>                  <TD>2107 miles</TD>                  <TD>1 days</TD              </TR>          </TABLE>      </BODY>  </HTML> 

You can see this document in Figure 4.3.

Figure 4.3. Using XPath predicates to check attributes.
graphics/04fig03.gif

In the following example, I copy planets.xml to a new XML document, and change the text in Venuss <NAME> element to "The Planet of Love" . To do that, I start by copying all nodes and attributes to the result document:

 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:output method="xml"/>    <xsl:template match="@*node()">      <xsl:copy>        <xsl:apply-templates select="@*node()"/>      </xsl:copy>    </xsl:template>          .          .          . 

Now Ill add a new rule that matches <NAME> elements that have the text Venus with the pattern "NAME[text() = 'Venus']" . Even though <NAME> elements match both rules in this stylesheet, the rule with the pattern "NAME[text() = 'Venus']" is a more specific match, so the XSLT processor uses it for Venuss <NAME> element:

 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:output method="xml"/>    <xsl:template match="@*node()">      <xsl:copy>        <xsl:apply-templates select="@*node()"/>      </xsl:copy>    </xsl:template>      <xsl:template match="NAME[text() = 'Venus']">          <NAME>              The Planet of Love          </NAME>      </xsl:template>  </xsl:stylesheet> 

And heres the result:

 <?xml version="1.0" encoding="utf-8"?>  <?xml-stylesheet type="text/xml" href="planets.xsl"?>  <PLANETS>      <PLANET>          <NAME>Mercury</NAME>          <MASS UNITS="(Earth = 1)">.0553</MASS>          <DAY UNITS="days">58.65</DAY>          <RADIUS UNITS="miles">1516</RADIUS>          <DENSITY UNITS="(Earth = 1)">.983</DENSITY>          <DISTANCE UNITS="million miles">43.4</DISTANCE><!--At perihelion-->      </PLANET>      <PLANET>          <NAME>              The Planet of Love          </NAME>          <MASS UNITS="(Earth = 1)">.815</MASS>          <DAY UNITS="days">116.75</DAY>          <RADIUS UNITS="miles">3716</RADIUS>          <DENSITY UNITS="(Earth = 1)">.943</DENSITY>          <DISTANCE UNITS="million miles">66.8</DISTANCE><!--At perihelion-->      </PLANET>      <PLANET>          <NAME>Earth</NAME>          <MASS UNITS="(Earth = 1)">1</MASS>          <DAY UNITS="days">1</DAY>          <RADIUS UNITS="miles">2107</RADIUS>          <DENSITY UNITS="(Earth = 1)">1</DENSITY>          <DISTANCE UNITS="million miles">128.4</DISTANCE><!--At perihelion-->      </PLANET>  </PLANETS> 

In fact, in XPath expressions, you can refer to the context node as ., and the default value of a node is its text, so the following rule works exactly the same way:

 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:output method="xml"/>    <xsl:template match="@*node()">      <xsl:copy>        <xsl:apply-templates select="@*node()"/>      </xsl:copy>    </xsl:template>      <xsl:template match="NAME[. = 'Venus']">          <NAME>              The Planet of Love          </NAME>      </xsl:template>  </xsl:stylesheet> 

Its worth packing in as many examples as possibleyou can never have too many match pattern or XPath examples. The following is a good collection of match pattern examples:

  • PLANET matches the <PLANET> element children of the context node.

  • /PLANETS matches the root element (PLANETS) of this document.

  • * matches all element children of the context node.

  • PLANET[3] matches the third <PLANET> child of the context node.

  • PLANET[last()] matches the last <PLANET> child of the context node.

  • PLANET[NAME] matches the <PLANET> children of the context node that have <NAME> children.

  • PLANET[DISTANCE]/NAME matches all <NAME> elements of <PLANET> elements that contain at least one <DISTANCE> element.

  • PLANET[DISTANCE]/PLANET[DAY] matches all <PLANET> elements of <PLANET> elements where the <PLANET> element contains at least one <DISTANCE> element, and the <PLANET> element has at least one <DAY> element.

  • PLANETS[PLANET/DAY] matches all <PLANETS> elements that have <PLANET> elements with at least one <DAY> element.

  • PLANET[DISTANCE][NAME] matches all <PLANET> elements that have <DISTANCE> and <NAME> elements.

  • PLANETS/PLANET[last()] matches the last <PLANET> in each <PLANETS> element.

  • */PLANET matches all <PLANET> grandchildren of the context node.

  • /PLANETS/PLANET[3]/NAME[2] matches the second <NAME> element of the third <PLANET> element of the <PLANETS> element.

  • //PLANET matches all the <PLANET> descendants of the document root.

  • PLANETS//PLANET matches the <PLANET> element descendants of the <PLANETS> element children of the context node.

  • //PLANET/NAME matches all the <NAME> elements that are children of a <PLANET> parent.

  • PLANETS//PLANET/DISTANCE//PERIHELION matches <PERIHELION> elements anywhere inside a <PLANET> elements <DISTANCE> element, anywhere inside a <PLANETS> element.

  • @UNITS matches the UNITS attribute of the context node.

  • @* matches all the attributes of the context node.

  • *[@UNITS] matches all elements with the UNITS attribute.

  • DENSITY/@UNITS matches the UNITS attribute in <DENSITY> elements.

  • PLANET[not(@COLOR) or not(@SIZE)] matches <PLANET> elements that do not have both COLOR and SIZE attributes.

  • PLANETS[@STAR="Sun"]//DENSITY matches any <DENSITY> element with a < PLANETS> ancestor element that has a STAR attribute set to Sun.

  • PLANET[NAME="Venus"] matches the <PLANET> children of the context node that have <NAME> children with text equal to Venus.

  • PLANET[NAME[1] = "Venus"] matches all <PLANET> elements where the text in the first <NAME> element is Venus.

  • DAY[@UNITS != "million miles"] matches all <PLANET> elements where the UNITS attribute is not million miles.

  • PLANET[@UNITS = "days"] matches all <PLANET> children of the context node that have a UNITS attribute with value days.

  • PLANET[6][@UNITS = "days"] matches the sixth <PLANET> child of the context node, only if that child has a UNITS attribute with value days. Can also be written as PLANET[@UNITS = "days"][6] .

  • PLANET[@COLOR and @UNITS] matches all the <PLANET> children of the context node that have both a COLOR attribute and a UNITS attribute.

  • *[1][NAME] matches any <NAME> element that is the first child of its parent.

  • *[position() &lt; 5] matches the first five children of the context node.

  • *[position() &lt; 5][@UNIT] matches the first five children of the context node with a UNITS attribute.

  • text() matches all text node children of the context node.

  • text()[ starts-with (., "In the course of human events")] matches all text nodes that are children of the context node and start with In the course of human events.

  • /PLANETS[@UNITS = "million miles"] matches all PLANETS where the value of the UNITS attribute is equal to million miles.

  • PLANET[/PLANETS/@UNITS = @REFERENCE] matches all <PLANET> elements where the value of the REFERENCE attribute is the same as the value of the UNITS attribute of the PLANETS element at the root of the document.

  • PLANET/* matches all element children of PLANET elements.

  • PLANET/*/DAY matches all DAY elements that are grandchildren of PLANET elements that are children of the context node.

  • */* matches the grandchildren elements of the current element.

  • astrophysics:PLANET matches the PLANET element in the astrophysics namespace.

  • astrophysics:* matches any elements in the astrophysics namespace.

  • PLANET[DAY and DENSITY] matches all <PLANET> elements that have at least one <DAY> and one <DENSITY> element.

  • PLANET[(DAY or DENSITY) and MASS] matches all <PLANET> elements that have at least one <DAY> or <DENSITY> element, and also have at least one <MASS> element.

  • PLANET[DAY and not(DISTANCE)] matches all <PLANET> elements that have at least one <DAY> element and no <DISTANCE> elements.

  • PLANET[MASS = /STANDARD/REFERENCE/MASS] matches all <PLANET> elements where the <MASS> elements value is the same as the value of the /<STANDARD>/<REFERENCE>/<MASS> element.

That completes this coverage of match patterns for the moment; youll see related material in Chapter 7 on XPath expressions. Chapter 5 starts looking at ways of working with the data in XML documents by sorting that data and using it to make choices based on data values.



Inside XSLT
Inside Xslt
ISBN: B0031W8M4K
EAN: N/A
Year: 2005
Pages: 196

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net