BizTalk Utilities CV ,   Jobs ,   Code library  
 
 
Page 7 of 15

 

Previous Page Table Of Contents Next Page

XSL Transformations, cont.

Specifying Patterns for the match Attribute

You can use an involved syntax with the <xsl:template> element's match attribute, and 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 specific XML 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 wanted 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>

Notice 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 grand-_children 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 attributes if you preface their name with @. Here's an example; in this case, I'll display the data in planets.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> elementto insert a space into the output document (more on <xsl:text> later):

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

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

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

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

</TR>

 

    <TR>

<TD>Venus</TD><TD>.815 (Earth = 1)</TD><TD>3716 miles</TD>

</TR>

 

    <TR>

<TD>Earth</TD><TD>1 (Earth = 1)</TD><TD>2107 miles</TD>

</TR>

 

</TABLE>

</BODY>

</HTML>

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 should not 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 another markup language might use, such as a <COMMENT> element.

Here's an example; planet.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:

<?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, where 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. The reason for that is that 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(), however, 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 that I used was for comments. If you turn off the default rule for text nodes by adding the previous two lines to the version of planets.xsl used in the previous example, the text of those text nodes does not go into the output document. 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 <? 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>

One of the major reasons that 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:

<?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 expressions like PLANET | PLANET//NAME, and you can use multiple | operators, such as 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:

              n  The value of an attribute in a given string

              n  The value of an element

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

              n  The position of a node in the node tree

Here are some examples:

              n  This expression matches <PLANET> elements that have child <NAME> _elements:

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

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

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

              n  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 in planets.xml a new attribute-_COLOR-which holds the planet's color:

<?xml version="1.0"?>

<?xml-stylesheet type="text/xml" href="planets.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:

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

Specifying Patterns for the select Attribute

I've taken a look at the kinds of expressions that you can use with the <xsl:template> element's match attribute. 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.

The select attribute uses XPath expressions, which is a W3C recommendation as of November 16, 1999. You can find the XPath specification at www.w3.org/TR/xpath.

We've seen that you can use the match attribute to find nodes by name, child element(s), attributes, or even descendant. We've also seen that you can make some tests to see whether elements or attributes have certain values. You can do all that and more with the XPath specification supported by the select attribute, including finding nodes by parent or sibling elements, as well as much more involved tests. XPath is much more of a true language than the expressions you can use with the match attribute; for example, XPath expressions can return not only lists of nodes, but also Boolean, string, and numeric values.

The XML for Java package has a handy example program, ApplyXPath.java, that enables you to apply an XPath expression to a _document and see what the results would be. This is great for testing. For _example, if I applied the XPath expression "PLANET/NAME" to planets.xml, here is what the result would look like, displaying the values of all <NAME> elements that are children of <PLANET> elements (the <output> tags are added by ApplyXPath):

%java ApplyXPath planets.xml PLANET/NAME

<output>

<NAME>Mercury</NAME><NAME>Venus</NAME><NAME>Earth</NAME></output>

XPath expressions are more powerful than the match expressions we've seen; for one thing, they're not restricted to working with the current node or child nodes because you can work with parent nodes, ancestor nodes, and more. Specifying what node you want to work in relation to is called _specifying an axis in XPath. I'll take a look at XPath syntax in detail next.

 

Page 7 of 15

 

Previous Page Table Of Contents Next Page
 

Recent Jobs

Sr. Software Engineer - Analytics
Immediate Mainframe openings for Ch
Immediate TANDEM-TAL openings for C
Immediate ASP.NET/C# Openings for C
Sr. Software Engineer

View all Jobs (Add yours)
View all CV (Add yours)



teleconferencing service
water softener
Teleconference
Host Department NOLIMIT Web Hosting
MSN
sunglasses
spoc


    Email TopXML  

Front Page Daily Stuff TopXML Forum XML blogs XML Newsgroups BizTalk Biztalk Utilities Biztalk Utilities Tutorial B2B SAP XML Microsoft .NET Dotnet System XML Soapformatter SQLXML XMLserializer XQuery PHP PHP SimpleXML PHP XML Dom PHP XML RPC PHP XSLT Java Java Java XML Xalan Microsoft ASP ASP Schemas XML SQL Server XML XMLDom XSL XSL Tutorial XSLT Stylesheets General Javascript CSS XHTML WAP