Up to this point, Ive used only the default version of <xsl:apply-templates> , like this:
<TABLE BORDER="2"> <TR> <TD>Name</TD> <TD>Mass</TD> <TD>Radius</TD> <TD>Day</TD> </TR> <xsl:apply-templates/> </TABLE>
Using <xsl:apply-templates/> alone simply makes the XSLT processor search for all templates that match the child nodes of the context node, and thats the default usage. However, sometimes thats not good enough, because you may want to apply templates in a specific order, or otherwise choose what templates to apply, and you do that with the select attribute of the <xsl:apply-templates/> .
For example, so far weve only recovered the value of each <MASS> , <DAY> , and <RADIUS> element using <xsl:value-of> :
<?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"> <TR> <TD><xsl:value-of select="NAME"/></TD> <TD><xsl:value-of select="MASS"/></TD> <TD><xsl:value-of select="RADIUS"/></TD> <TD><xsl:value-of select="DAY"/></TD> </TR> </xsl:template> </xsl:stylesheet>
This just gets the raw string value of each node and places it into the HTML table. On the other hand, you might want to do more processing for each elementfor example, you might also want to get the value of the UNITS attributes in each element and display those values as well:
<?xml version="1.0"?> <?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> . . .
To do that, you cant just use <xsl:value-of> because it would return the node value only as text, not as attribute values. Instead, you have to create a new set of templates, one for each of the elements that you are interested in: <MASS> , <RADIUS> , and <DAY> . The <NAME> element doesnt have any attributes, so no template is needed thereyou need only the node value. Each of these new templates needs to get the value of the element, as well as the value of the UNITS attribute.
To make sure that these new templates are applied in the correct order to match the headings in the HTML table, Ill list each of these new templates explicitly, selecting them one by one with the select attribute:
<?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"> <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:stylesheet>
Using Named TemplatesIn addition to selecting templates this way, you can also call named templates by name. Youll see how that works in Chapter 9. |
Now that youre applying a new template for each of the <MASS> , <RADIUS> , and <DAY> elementsnot just getting the nodes string value with <xsl:value-of> you can do more processing on each of these elements, such as reading the values of their UNITS attributes. Ill start by getting the string value of each of the <MASS> , <RADIUS> , and <DAY> elements. Now that we have a template for each of these element nodes, and each node is the context node in its template, instead of referring to the element node by name, we now refer to it as the context node with the XPath expression .:
<?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"> <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:template> <xsl:template match="RADIUS"> <xsl:value-of select="."/> </xsl:template> <xsl:template match="DAY"> <xsl:value-of select="."/> </xsl:template> </xsl:stylesheet>
That just reproduces what weve done before with the previous version of planets.xsl, which uses <xsl:value-of select="MASS"> , <xsl:value-of select="RADIUS"> , and so onthat is, it reads and displays the data in each <MASS> , <RADIUS> , and <DAY> element. However, now that you have an individual template for each of those elements, you can do more processing, such as reading the values of attributes.