12.2 The choose and when Elements

The difference between if and choose is that choose allows you to test one or more conditions in a single structure while if allows you to test only one condition at a time. A choose element has no attributes, but it must have one or more when children. Similar to if, the when element has a single required test attribute that returns a Boolean.

The combination of choose with a single when child works the same way that a lone if element works. Example 12-6 demonstrates this, in the stylesheet choose.xsl.

Example 12-6. Using choose rather than if
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/>     <xsl:template match="africa">  <xsl:apply-templates select="nation"/> </xsl:template>     <xsl:template match="nation">  <xsl:choose>   <xsl:when test="population > 10000000">    <xsl:value-of select="name"/>    <xsl:text>&#10;</xsl:text>   </xsl:when>  </xsl:choose> </xsl:template>     </xsl:stylesheet>

Apply this to africa.xml:

xalan africa.xml choose.xsl

and you will get a plain list of African nations with populations exceeding 10,000,000:

Algeria Angola Burkina Faso Cameroon Congo, Democratic Republic of Cote d'Ivoire Eqypt Ethiopia Ghana Kenya Madagascar Malawi Mali Morocco Mozambique Niger Nigeria Senegal South Africa Sudan Tanzania Uganda Zimbabwe

The stylesheet when.xsl adds another when element to the template in choose.xsl so that the stylesheet can test another condition: which nations have less than 10,000,000 inhabitants. Example 12-7 shows this stylesheet.

Example 12-7. Using two when elements
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/>     <xsl:template match="africa">  <xsl:apply-templates select="nation"/> </xsl:template>     <xsl:template match="nation">  <xsl:choose>   <xsl:when test="population > 10000000">    <xsl:text>&#10;</xsl:text>    <xsl:value-of select="name"/>    <xsl:text> </xsl:text>   </xsl:when>   <xsl:when test="population &lt;= 10000000">    <xsl:text>[Skip] </xsl:text>   </xsl:when>  </xsl:choose> </xsl:template>     </xsl:stylesheet>

When this stylesheet encounters population nodes whose content is greater than 10,000,000, the name of the nation is written to the result tree; when it encounters population nodes whose content is less than or equal to 10,000,000, only a bit of text is written ([Skip]).

Test this stylesheet with africa.xml using:

xalan africa.xml when.xsl

to get the following output:

Algeria Angola [Skip] [Skip] Burkina Faso [Skip] Cameroon [Skip] [Skip] [Skip] [Skip] [Skip] Congo, Democratic Republic of Cote d'Ivoire [Skip] Eqypt [Skip] [Skip] Ethiopia [Skip] [Skip] Ghana [Skip] [Skip] Kenya [Skip] [Skip] [Skip] Madagascar Malawi Mali [Skip] [Skip] Morocco Mozambique [Skip] Niger Nigeria [Skip] [Skip] Senegal [Skip] [Skip] [Skip] South Africa Sudan [Skip] Tanzania [Skip] [Skip] Uganda [Skip] Zimbabwe

The test attribute in the when elements checks whether certain nodes match certain criteria; if they do, the template in the when element is instantiated. The occurrences of [Skip] help you to see where nodes were skipped.

12.2.1 The otherwise Element

When programming, it's possible that none of the conditions you test are true, so the language has to handle that case. In FORTRAN 77, for example, a final ELSE statement provides an escape hatch when nothing else works:

    IF(POPULATION .GT. 10000000) THEN       PRINT *, NAME     ELSE IF(POPULATION .LT. 10000000) THEN       PRINT *, MSG       PRINT *, NAME     ELSE       GO TO 100     END IF 100 STOP     END

In this statement, if neither of the conditions are met (are true), execution jumps to the line labeled 100 in the program where execution stops, and the program ends.

In Java, you could write a similar statement as follows:

if (population > 10000000) {     System.out.println(name); } else if (population < 10000000) {     System.out.println(msg);     System.out.println(name); } else {     System.exit(1); }

If both Booleans fail, the last statement executes and exits out of the program. The otherwise element in XSLT takes on the role of the escape hatch, just as the ELSE or else statements take on the role in FORTRAN or Java. The otherwise.xsl stylesheet, shown in Example 12-8, demonstrates how this is done.

Example 12-8. Using otherwise to terminate stylesheet execution
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/>     <xsl:template match="africa">  <xsl:apply-templates select="nation"/> </xsl:template>     <xsl:template match="nation">  <xsl:choose>   <xsl:when test="population = 10000000">    <xsl:value-of select="name"/>    <xsl:text> = 10M</xsl:text>    <xsl:text>&#10;</xsl:text>   </xsl:when>   <xsl:when test="population = 1000000">    <xsl:value-of select="name"/>    <xsl:text> = 1M</xsl:text>    <xsl:text>&#10;</xsl:text>   </xsl:when>   <xsl:otherwise>    <xsl:message terminate="yes">Not found!</xsl:message>   </xsl:otherwise>  </xsl:choose> </xsl:template>     </xsl:stylesheet>

The test attributes on when elements check whether a population element has content that equals 10,000,000 or 1,000,000. None of the population elements in africa.xml will satisfy these tests, so the control in the choose structure drops down to the otherwise element.

At that point, the processor encounters a message element. A message element outputs a message to the screen (standard output), not to the result tree, and so it is a good way to create status or error messages. (The destination of such messages is left undefined in the XSLT spec, but generally XSLT processors send them to the screen.)

Commonly, stylesheet developers use message elements inside fallback elements. Chapter 15 discusses how to use message and fallback elements together.


12.2.2 Processing More Than One Kind of Document

Imagine that you want to efficiently process several kinds of XML documents, each containing similar content, but each using a different vocabulary. The document africa2.xml is structured just like africa.xml, but uses verbose element names. Example 12-9 shows part of africa2.xml.

Example 12-9. A version of the African countries document using verbose markup
<?xml version="1.0" encoding="ISO-8859-1"?>     <continent.africa>  <continent.africa.country>   <continent.africa.country.name>Algeria</continent.africa.country.name>   <continent.africa.country.capital>Algiers</continent.africa.country.capital>   <continent.africa.country.population>32277942</continent.africa.country.population>   <continent.africa.country.code>dz</continent.africa.country.code>  </continent.africa.country>  <continent.africa.country>   <continent.africa.country.name>Angola</continent.africa.country.name>   <continent.africa.country.capital>Luanda</continent.africa.country.capital>   <continent.africa.country.population>10593171</continent.africa.country.population>   <continent.africa.country.code>ao</continent.africa.country.code>  </continent.africa.country>  <continent.africa.country>   <continent.africa.country.name>Benin</continent.africa.country.name>   <continent.africa.country.capital>Porto-Novo</continent.africa.country.capital>   <continent.africa.country.population>6787625</continent.africa.country.population>   <continent.africa.country.code>bj</continent.africa.country.code>  </continent.africa.country>  <continent.africa.country>   <continent.africa.country.name>Bostwana</continent.africa.country.name>   <continent.africa.country.capital>Gaborone</continent.africa.country.capital>   <continent.africa.country.population>1591232</continent.africa.country.population>   <continent.africa.country.code>bw</continent.africa.country.code>  </continent.africa.country>  <continent.africa.country>   <continent.africa.country.name>Burkina Faso</continent.africa.country.name>   <continent.africa.country.capital>Ouagadougou</continent.africa.country.capital>   <continent.africa.country.population>12603185</continent.africa.country.population>   <continent.africa.country.code>bf</continent.africa.country.code>  </continent.africa.country>

The document has a structure that is similar to africa.xml but uses long, structured element names. Using choose, when, and otherwise elements, Example 12-10, the stylesheet dual.xsl, can process similar elements in both africa.xml and africa2.xml, plus handle nonconforming documents that it encounters.

Example 12-10. A stylesheet that tests for multiple element names explicitly
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="ISO-8859-1"/>     <xsl:template match="africa | continent.africa">  <xsl:apply-templates select="nation[10] | continent.africa.country[10]"/> </xsl:template>     <xsl:template match="nation | continent.africa.country">  <xsl:choose>   <xsl:when test="name = 'Chad'">    <xsl:apply-templates select="name"/>   </xsl:when>   <xsl:when test="continent.africa.country.name = 'Chad'">    <xsl:apply-templates select="continent.africa.country.name"/>   </xsl:when>   <xsl:otherwise>    <xsl:message terminate="yes">Not found!</xsl:message>   </xsl:otherwise>  </xsl:choose> </xsl:template>     <xsl:template match="name | continent.africa.country.name">  <xsl:value-of select="name(  )"/>  <xsl:text>: </xsl:text>  <xsl:value-of select="."/>  <xsl:text>&#10;</xsl:text> </xsl:template>     </xsl:stylesheet>

The templates in dual.xsl can match parallel elements in either africa.xml or africa2.xml. The first template, for example, matches either an africa or a continent.africa element, the document elements of africa.xml and africa2.xml, respectively. The second template, which matches nation or continent.africa.country elements, uses choose and when to find the tenth matching child name or continent.africa.country.name node. If it finds one or the other of those nodes, it processes them with a third template, which inserts the node name and content into the result tree. If neither node is found, the stylesheet handles the problem with a message element inside an otherwise element. The message element also terminates processing.

I'll process this example with xsltproc. (You saw this processor once before in Chapter 10.) When I enter the following command line:

xsltproc dual.xsl africa.xml africa2.xml truncated.xml

it gives this result:

name: Chad continent.africa.country.name: Chad Not found!

Because it accepts a stylesheet first, then the XML documents after that, you can process more than one XML document at a time with xsltproc. You can see from the output that each document yields a different result. The document truncated.xml has only 10 nation elements, but none with a name child that matches Chad, so it generates the Not found! message.

This stylesheet should help you write other stylesheets that process more than one kind of document but produce similar results. This is just one way to get that job done. For illustration, Example 12-11 is a stylesheet that produces the same results, but it is written more tightly. It's called dual2.xsl.

Example 12-11. Refining Example 12-10
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="ISO-8859-1"/>     <xsl:template match="africa | continent.africa">  <xsl:apply-templates select="nation[10] | continent.africa.country[10]"/> </xsl:template>     <xsl:template match="nation | continent.africa.country">  <xsl:choose>   <xsl:when test="(name|continent.africa.country.name) = 'Chad'">    <xsl:apply-templates select="name|continent.africa.country.name"/>   </xsl:when>   <xsl:otherwise>    <xsl:message terminate="yes">Not found!</xsl:message>   </xsl:otherwise>  </xsl:choose> </xsl:template>     <xsl:template match="name | continent.africa.country.name">  <xsl:value-of select="name(  )"/>  <xsl:text>: </xsl:text>  <xsl:value-of select="."/>  <xsl:text>&#10;</xsl:text> </xsl:template>     </xsl:stylesheet>

The difference between dual.xsl and dual2.xsl is that dual.xsl has two when elements, whereas dual2.xsl has only one. The test attribute of the single when element in dual2.xsl returns true for either name or (|) continent.africa.country.name elements, depending on the source tree. So one when element, when used with |, does the job of two. Try it with this command:

xsltproc dual2.xsl africa.xml africa2.xml truncated.xml

and you will get the same result as you did with dual.xsl.



Learning XSLT
Learning XSLT
ISBN: 0596003277
EAN: 2147483647
Year: 2003
Pages: 164

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