Specifying Patterns for the match Attribute

Specifying Patterns for the match Attribute

You can use an involved syntax with the <xsl:template> element's match attribute, and you can use an even more involved syntax with the select attribute of the <xsl:apply-templates> , <xsl:value-of> , <xsl:for-each> , <xsl:copy-of> , and <xsl: sort > elements. We'll see them both in this chapter, starting with the syntax you can use with the match attribute.

Matching the Root Node

As we've already seen, you can match the root node with / , like this:

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

Matching Elements

You can match elements simply by giving their name , as we've also seen:

  <xsl:template match="PLANETS">  <HTML>     <xsl:apply-templates/>   </HTML> </xsl:template> 

Matching Children

You can use the / operator to separate element names when you want to refer to a child of a particular node. For example, say that you want to create a rule that applies only to <NAME> elements that are children of <PLANET> elements. In that case, you can match to the expression "PLANET/NAME" . Here's a rule that will surround the text of such elements in an <H3> element:

 <xsl:template match="PLANET/NAME">    <H3><xsl:value-of select="."/></H3> </xsl:template> 

Note the expression "." here. You use "." with the select attribute to specify the current node, as we'll see when discussing the select attribute.

You can also use the * character as a wildcard, standing for any element ( * can match only elements). For example, this rule applies to all <NAME> elements that are grandchildren of <PLANET> elements:

 <xsl:template match="PLANET/*/NAME">    <H3><xsl:value-of select="."/></H3> </xsl:template> 

Matching Element Descendants

In the previous section, I used the expression "PLANET/NAME" to match all <NAME> elements that are direct children of <PLANET> elements, and I used the expression "PLANET/*/NAME" to match all <NAME> elements that are grandchildren of <PLANET> elements. However, there's an easier way to perform both matches: Just use the expression "PLANET//NAME" , which matches all <NAME> elements that are inside <PLANET> elements, no matter how many levels deep (the matched elements are called descendants of the <PLANET> element). In other words, "PLANET//NAME" matches "PLANET/NAME" , "PLANET/*/NAME" , "PLANET/*/*/NAME" , and so on:

 <xsl:template match="PLANETS//NAME">    <H3><xsl:value-of select="."/></H3> </xsl:template> 

Matching Attributes

You can match an attribute if you preface its name with @ . Here's an example; in this case, I'll display the data in ch13_01.xml in an HTML table. You might note, however, that the units for the various measurements are stored in attributes, like this:

 <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> 

To recover the units and display them as well as the values for the mass and so on, I'll match the UNITS attribute with @UNITS . Here's how that looks. Note that I'm using the element <xsl:text> to insert a space into the output document (more on <xsl:text> later):

Listing ch13_09.xsl
 <?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="1">                     <TD>Name</TD>                     <TD>Mass</TD>                     <TD>Radius</TD>                     <TD>Day</TD>                     <xsl:apply-templates/>                 </TABLE>             </BODY>         </HTML>     </xsl:template>     <xsl:template match="PLANET">        <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="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> 

Now the resulting HTML table includes not only values, but also their units of measurement. (The spacing leaves a little to be desired, but HTML browsers will have no problem with it; we'll take a look at ways of handling whitespace later in this chapter.)

 <HTML>  <HEAD> <TITLE>                     The Planets Table                 </TITLE> </HEAD> <BODY> <H1>                     The Planets Table                 </H1> <TABLE BORDER="1"> <TD>Name</TD><TD>Mass</TD><TD>Radius</TD><TD>Day</TD> <TR> <TD>Mercury</TD><TD>.0553 (Earth = 1)</TD><TD>1516 miles</TD><TD>58.65 days</TD> </TR> <TR> <TD>Venus</TD><TD>.815 (Earth = 1)</TD><TD>3716 miles</TD><TD>116.75 days</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 result in Figure 13-3 in Internet Explorer.

Figure 13-3. An XSL transformation that creates an HTML table.

graphics/13fig03.gif

You can also use the @* wildcard to select all attributes of an element. For example, "PLANET/@*" selects all attributes of <PLANET> elements.

Matching by ID

You can also match elements that have a specific ID value using the pattern id() . To use this selector, you must give elements an ID attribute, and you must declare that attribute of type ID, as you can do in a DTD. Here's an example rule that adds the text of all elements that have the ID Christine :

 <xsl:template match = "id('Christine')">      <H3><xsl:value-of select="."/></H3> </xsl:template> 

Matching Comments

You can match the text of comments with the pattern comment() . You shouldn't store data that should go into the output document in comments in the input document, of course. However, you might want to convert comments from the <!-- comment --> form into something that another markup language might use, such as a <COMMENT> element.

Here's an example; ch13_01.xml was designed to include comments so that we could see how to extract them:

 <PLANET>      <NAME>Venus</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> 

To extract comments and put them into <COMMENT> elements, I'll include a rule just for comments:

Listing ch13_10.xsl
 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:template match="PLANETS">         <HTML>             <xsl:apply-templates/>         </HTML>     </xsl:template>  <xsl:template match="comment()">   <COMMENT>   <xsl:value-of select="."/>   </COMMENT>   </xsl:template>  </xsl:stylesheet> 

Here's what the result is for Venus; I've transformed the comment into a <COMMENT> element:

 Venus  .815 116.75 3716 .943 66.8<COMMENT>At perihelion</COMMENT> 

Note that the text for the other elements in the <PLANET> element is also inserted into the output document. This is because the default rule for each element is to include its text in the output document. Because I haven't provided a rule for elements, their text is simply included in the output document. I'll take a closer look at default rules later in the chapter.

Matching Text Nodes with text()

You can match the text in a node with the pattern text() . There's really not much reason to ever use text() because XSLT includes a default rule: If there are no other rules for a text node, the text in that node is inserted into the output document. If you were to make that default rule explicit, it might look like this:

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

You can override this rule by not sending the text in text nodes to the output document, like this:

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

In the previous example, you can see that a great deal of text made it from the input document to the output document because there was no explicit rule besides the default one for text nodes: The only output rule I used was for comments. If you turn off the default rule for text nodes by adding the previous two lines to ch13_10.xsl, the text of those text nodes does not go into the output document, and this is the result:

 <HTML>  <COMMENT>At perihelion</COMMENT> <COMMENT>At perihelion</COMMENT> <COMMENT>At perihelion</COMMENT> </HTML> 

Matching Processing Instructions

You can use the pattern processing-instruction() to match processing instructions.

  <xsl:template match="/processing-instruction()">  <I>         Found a processing instruction.     </I> </xsl:template> 

You can also specify what processing instruction you want to match by giving the name of the processing instruction (excluding the <? and ?> ), as in this case, where I'm matching the processing instruction <?xml-include?> :

  <xsl:template match="/processing-instruction(xml-include)">  <I>         Found an xml-include processing instruction.     </I> </xsl:template> 

Distinction Between Root Node and Document Node

One of the major reasons why XML makes a distinction between the root node at the very beginning of the document and the document node is so that you have access to the processing instructions and other nodes in the document's prolog.

Using the Or Operator

You can match to a number of possible patterns, which is very useful when your documents get a little more involved than the ones we've been using so far in this chapter. Here's an example. In this case, I want to display <NAME> and <MASS> elements in bold, which I'll do with the HTML <B> tag. To match either <NAME> or <MASS> elements, I'll use the Or operator, which is a vertical bar ( ) in a new rule, like this:

Listing ch13_11.xsl
 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:template match="PLANETS">         <HTML>             <xsl:apply-templates/>         </HTML>     </xsl:template>     <xsl:template match="PLANET">         <P>             <xsl:apply-templates/>         </P>     </xsl:template>  <xsl:template match="NAME  MASS">   <B>   <xsl:apply-templates/>   </B>   </xsl:template>  </xsl:stylesheet> 

Here are the results. Note that the name and mass values are both enclosed in <B> elements. (Also note that, because of the XSL default rules, the text from the other child elements of the <PLANET> element is also displayed.)

 <HTML>    <P>     <B>Mercury</B>     <B>.0553</B>     58.65     1516     .983     43.4   </P>   <P>     <B>Venus</B>     <B>.815</B>     116.75     3716     .943     66.8   </P>   <P>     <B>Earth</B>     <B>1</B>     1     2107     1     128.4   </P> </HTML> 

You can use any valid pattern with the operator, such as the expressions PLANET PLANET//NAME . You also can use multiple operators, as in NAME MASS DAY , and so on.

Testing with []

You can use the [] operator to test whether a certain condition is true. For example, you can test the following:

  • Whether the value of an attribute is a given string

  • The value of an element

  • Whether an element encloses a particular child, attribute, or other element

  • The position of a node in the node tree

Here are some examples. This expression matches <PLANET> elements that have child <NAME> elements:

 <xsl:template match = "PLANET[NAME]"> 

This expression matches any element that has a <NAME> child element:

 <xsl:template match = "*[NAME]"> 

This expression matches any <PLANET> element that has either a <NAME> or a <MASS> child element:

 <xsl:template match="PLANET[NAME  MASS]"> 

Say that we gave the <PLANET> elements a new attribute COLOR , which holds the planet's color:

Listing ch13_12.xml
 <?xml version="1.0"?> <?xml-stylesheet type="text/xml" href="ch13_02.xsl"?> <PLANETS>  <PLANET COLOR="RED">  <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 COLOR="WHITE">  <NAME>Venus</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 COLOR="BLUE">  <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> 

This expression matches <PLANET> elements that have COLOR attributes:

 <xsl:template match="PLANET[@COLOR]"> 

What if you wanted to match planets whose COLOR attribute was "BLUE" ? You can do that with the = operator, like this:

Listing ch13_13.xsl
 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:template match="PLANETS">         <HTML>             <xsl:apply-templates/>         </HTML>     </xsl:template>  <xsl:template match="PLANET[@COLOR = 'BLUE']">   The <xsl:value-of select="NAME"/> is blue.   </xsl:template>  <xsl:template match="text()">     </xsl:template> </xsl:stylesheet> 

This style sheet filters out all planets whose color is blue and omits the others by turning off the default rule for text nodes. Here's the result:

 <HTML>              The Earth is blue.     </HTML> 

In fact, the expressions you can use in the [] operators are W3C XPath expressions. XPath expressions give you ways of specifying nodes in an XML document using a fairly involved syntax. And because the select attribute, which we're about to cover, uses XPath, I'll take a look at XPath as well.



Real World XML
Real World XML (2nd Edition)
ISBN: 0735712867
EAN: 2147483647
Year: 2005
Pages: 440
Authors: Steve Holzner

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