Attribute Value Templates - Page 8
November 2, 2001
You can do a lot with attribute value templates. For example,
these templates make converting elements to attributes simple.
The @ character makes it easy to insert an attribute
value where that value will be used as element content in the
result. To demonstrate this, let's convert the grape attribute in
the following to a product subelement of the
wine element. While we're at it, we'll convert the
year subelement to a vintage attribute.
<wine grape="Chardonnay">
<product>Carneros</product>
<year>1997</year>
<price>10.99</price>
</wine>
The result should look like this:
<wine vintage="1997">
<product>Carneros</product>
<category>Chardonnay</category>
<price>10.99</price>
</wine>
The following template converts the grape attribute into a
category subelement by using the @
character, and the message uses the xsl:value-of
element to put each grape attribute value between a
pair of category start- and end-tags. (As with
attribute value templates, an XSLT processor takes what the
xsl:value-of element hands it in its
select attribute, evaluates it, and adds the result
to the appropriate place on the result tree.)
<!-- xq33.xsl: converts xq31.xml into xq32.xml. -->
<xsl:template match="wine">
<wine vintage="{year}">
<product><xsl:apply-templates select="product"/></product>
<category><xsl:value-of select="@grape"/></category>
<price><xsl:apply-templates select="price"/></price>
</wine>
</xsl:template>
To convert an element to an attribute, the same template uses an
attribute value tem-plate— the curly braces around "year"—to put
the source tree wine element's year subelement after
vintage= in the result tree's wine
element.
Another great trick is selective processing of elements based on
an attribute value. Because an XSLT processor applies the most
specific template it can find in the stylesheet for each source
tree node, it will apply the first template in the following
stylesheet for each wine element that has a value of
"Cabernet" in its grape attribute, and the second for all the
other wine elements. (The [@grape='Cabernet'] part
that specifies this is a special part of a match pattern or XPath
expression called a "pred-icate.") The first template copies the
element, while the second doesn't. The output will therefore only
have wines with "Cabernet" as their grape value.
<!-- xq34.xsl -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="wine[@grape='Cabernet']">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>
<xsl:template match="wine"/>
<xsl:template match="@*|node()|processing-instruction()|comment()">
<xsl:copy>
<xsl:apply-templates
select="@*|node()|processing-instruction()|comment()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
How useful is this? Think about the importance of a database
system's ability to extract subsets of data based on certain
criteria. The creation of such customized reports can be the main
reason for developing a database in the first place. The ability
to generate customized publications and reports from your XML
documents can give you similar advantages in a system that uses
those documents, because the more you can re-use the document
components in different permutations, the more value the
documents have.
For related information, see
- chapter 2, "XPath," on page 23 for more on the use of
expressions in square brackets ("predicates") to filter out a
subset of the nodes that you want
- section 3.5, "Converting elements to attributes for the
result tree," page 55
- section 3.8, "Deleting elements from the result tree," page
63
- section 3.14, "Converting attributes to elements," page 79
|