As you saw earlier, a variable value, created with a template as element content, creates a result tree fragment. The stylesheet in Example 7-2, fragment.xsl, constructs a variable value for discount using a template with a variable element, and then later accesses that value with copy-of. Example 7-2. Copying a variable<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:output doctype-system="catalog.dtd"/> <xsl:variable name="discount"> <discount>0.40</discount> <discountPrice><xsl:value-of select="format-number(catalog/item/price * 0.60, '###.00')"/></discountPrice> </xsl:variable> <xsl:template match="catalog"> <xsl:copy> <xsl:apply-templates select="item"/> </xsl:copy> </xsl:template> <xsl:template match="item"> <xsl:copy> <xsl:copy-of select="@id"/> <xsl:copy-of select="maker|description|size|price"/> <xsl:copy-of select="$discount"/> <xsl:copy-of select="currency"/> </xsl:copy> </xsl:template> </xsl:stylesheet> Notice the value-of contained in discountPrice in variable. The first argument of format-number( ) uses a location path to address the content of the price element in the source tree. The context node for evaluating a global variable is the root node of the original source document; that's why the location path uses catalog/item/price instead of /catalog/item/price, an absolute location path. Later, in the template for item, copy-of elements copy the id attribute from the source item and the nodes contained in discount's result tree fragment. To test it out, enter this command line: saxon price.xml fragment.xsl You will get this outcome: <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE catalog SYSTEM "catalog.dtd"> <catalog> <item > <maker>Scratchmore</maker> <description>Wool sweater</description> <size>L</size> <price>120.00</price> <discount>0.40</discount> <discountPrice>72.00</discountPrice> <currency>USD</currency> </item> </catalog> A result tree fragment does not have to be well-formed XML. For example, you could also just use a bit of text in a result tree fragment, as shown in the variable definition for discount in Example 7-3, frag.xsl. Example 7-3. Using text as a result tree fragment<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:output doctype-system="catalog.dtd"/> <xsl:variable name="discount">0.70</xsl:variable> <xsl:variable name="discountPrice" select="format-number(catalog/item/price - (catalog/item/price) * $discount, '###.00')"/> <xsl:template match="catalog"> <xsl:copy> <xsl:apply-templates select="item"/> </xsl:copy> </xsl:template> <xsl:template match="item"> <xsl:copy> <xsl:copy-of select="@id"/> <xsl:copy-of select="maker|description|size|price"/> <discount><xsl:value-of select="$discount"/></discount> <discountPrice><xsl:value-of select="$discountPrice"/></discountPrice> <xsl:copy-of select="currency"/> </xsl:copy> </xsl:template> </xsl:stylesheet> The variable discount contains only the text 0.70. (It's not best to define a simple value like 0.70 as a tree fragment, as it is somewhat more costly processing-wise to do so.) When the discountPrice variable is defined, it contains a reference to discount as part of its definition. The two variables are referenced later in the stylesheet by instances of value-of.
Watch what happens with this command: xalan -i 1 price.xml frag.xsl Here is the result: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE catalog SYSTEM "catalog.dtd"> <catalog> <item > <maker>Scratchmore</maker> <description>Wool sweater</description> <size>L</size> <price>120.00</price> <discount>0.70</discount> <discountPrice>36.00</discountPrice> <currency>USD</currency> </item> </catalog> Before concluding, I should mention a few more things about result tree fragments. Only XSLT 1.0 allows you to copy result tree fragments or use them as strings. However, the node-set( ) extension function offered by many XSLT 1.0 processors allows you to use a result tree fragment as a tree of temporary nodes. node-set( ) is not actually part of XSLT 1.0, but it is a useful extension added by many XSLT processors. You will learn how to use two versions of node-set( ) in Chapter 15. XSLT 2.0 uses temporary trees rather than result tree fragments, which are stricter. Unlike its 1.0 predecessor, XSLT 2.0 is a tree of XML nodes and cannot contain mere fragments of text. |