Modes: Context-Specific Formatting

Modes: Context-Specific Formatting

Sometimes, matching nodes can be an art. For example, a template that matches * also matches PLANET. However, if you want <PLANET> elements handled differently than all other elements, you can set up a template that matches PLANET; the XSLT processor, knowing PLANET is a closer match to a <PLANET> element than *, uses the PLANET match. On the other hand, sometimes things arent so clear. For example, you may want PLANETS to match some <PLANET> elements, but not others. One way of making sure that happens is to use modes .

You can use the mode attribute of <xsl:apply-templates> to set a processing mode. When you set a mode, the only templates that match are those <xsl:template> elements that have their mode attribute set to the same mode. In this way, you can make templates match only one particular node, even if otherwise they would match many nodes. Thats great, for example, if you want to handle some <PLANET> elements differently from others.

The following example shows how this works. In this case, I create a new processing mode for planets called fancy that displays planetary data in bold. However, I just want the Earths planetary data to appear in bold, and not any of the other planets data. That could be a problem, because all the data for the planets are stored in the same type of element <PLANET> so theyre all matched by the pattern PLANET. However, I can use modes to solve this problem. In particular, if the current planet is Earth, I can set the processing mode to fancy:

 <?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">         <xsl:if test="NAME='Earth'">         <TR>            <TD><xsl:apply-templates select="NAME" mode="fancy"/></TD>            <TD><xsl:apply-templates select="MASS" mode="fancy"/></TD>            <TD><xsl:apply-templates select="RADIUS" mode="fancy"/></TD>            <TD><xsl:apply-templates select="DAY" mode="fancy"/></TD>         </TR>         </xsl:if>         <xsl:if test="NAME!='Earth'">         <TR>            <TD><xsl:apply-templates 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:if>     </xsl:template>          .          .          . 

Then I set up the template rules I want, both for the fancy processing mode, which bolds its output, and no special processing mode:

Listing 6.13 Using Modes
 <?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 Fancy Planets Table                  </TITLE>              </HEAD>              <BODY>                  <H1>                      The Fancy 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">         <xsl:if test="NAME='Earth'">         <TR>            <TD><xsl:apply-templates select="NAME" mode="fancy"/></TD>            <TD><xsl:apply-templates select="MASS" mode="fancy"/></TD>            <TD><xsl:apply-templates select="RADIUS" mode="fancy"/></TD>            <TD><xsl:apply-templates select="DAY" mode="fancy"/></TD>         </TR>         </xsl:if>         <xsl:if test="NAME!='Earth'">         <TR>            <TD><xsl:apply-templates 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:if>     </xsl:template>      <xsl:template match="NAME">          <xsl:value-of select="."/>      </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:template match="NAME" mode="fancy">          <B><xsl:value-of select="."/></B>      </xsl:template>      <xsl:template match="MASS" mode="fancy">          <B>              <xsl:value-of select="."/>              <xsl:text> </xsl:text>              <xsl:value-of select="@UNITS"/>          </B>      </xsl:template>      <xsl:template match="RADIUS" mode="fancy">          <B>              <xsl:value-of select="."/>              <xsl:text> </xsl:text>              <xsl:value-of select="@UNITS"/>          </B>      </xsl:template>      <xsl:template match="DAY" mode="fancy">          <B>              <xsl:value-of select="."/>              <xsl:text> </xsl:text>              <xsl:value-of select="@UNITS"/>          </B>      </xsl:template>  </xsl:stylesheet> 

Heres the result. Note that Earths data, and only Earths data, is made bold:

 <HTML>      <HEAD>          <TITLE>              The Fancy Planets Table          </TITLE>      </HEAD>      <BODY>          <H1>              The Fancy 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>              <TR>                  <TD>Venus</TD>                  <TD>.815 (Earth = 1)</TD>                  <TD>3716 miles</TD>                  <TD>116.75 days</TD>              </TR>              <TR>                  <TD><B>Earth</B></TD>                  <TD><B>1 (Earth = 1)</B></TD>                  <TD><B>2107 miles</B></TD>                  <TD><B>1 days</B></TD>              </TR>          </TABLE>      </BODY>  </HTML> 

You can see this result in Figure 6.4.

Figure 6.4. Using processing modes.
graphics/06fig04.gif

Modes are also very useful when you want to process the same document more than once, and the classic example is when youre creating a table of contents.

The following example shows how that works; in this case, I add a table of contents to planets.xml in a <TOC> element that has three <ENTRY> elements, one for each planet. Note that I have to use two templates that match <PLANET> elements here, one to create the table of contents and one to copy over all <PLANET> elements to the result document, so I use modes to keep them straight. I start by setting the mode to toc and using a template that supports that mode and creates the table of contents:

 <?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="PLANETS">      <PLANETS>          <TOC>              <xsl:apply-templates mode="toc"/>          </TOC>          .          .          .      </PLANETS>    </xsl:template>    <xsl:template match="PLANET" mode="toc">      <ENTRY>          <xsl:value-of select="NAME"/>      </ENTRY>    </xsl:template>          .          .          . 

Next , I apply a general template without any processing modes to all elements and attributes so I can copy them to the result document:

Listing 6.14 Creating a Table of Contents
 <?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="PLANETS">      <PLANETS>          <TOC>              <xsl:apply-templates mode="toc"/>          </TOC>          <xsl:apply-templates select="@*node()"/>      </PLANETS>    </xsl:template>    <xsl:template match="PLANET" mode="toc">      <ENTRY>          <xsl:value-of select="NAME"/>      </ENTRY>    </xsl:template>    <xsl:template match="@*node()">      <xsl:copy>        <xsl:apply-templates select="@*node()"/>      </xsl:copy>    </xsl:template>  </xsl:stylesheet> 

And heres the result, showing planets.xml with a table of contents:

 <?xml version="1.0" encoding="UTF-8"?>  <?xml-stylesheet type="text/xml" href="planets.xsl"?>  <PLANETS>      <TOC>          <ENTRY>Mercury</ENTRY>          <ENTRY>Venus</ENTRY>          <ENTRY>Earth</ENTRY>      </TOC>      <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>          .          .          .  </PLANETS> 

This chapter has covered a lot of ground, and in the next chapter Im going to press on, taking a look at creating full XPath expressions. Although you got a taste of this topic when you saw match patterns created in Chapter 4, theres a great deal more coming up.



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