Often it is useful to filter and sort data without translating to a new schema. The <xsl:copy> element makes it possible to write a simple identity transformation. Additional templates that sort or filter particular parts of the data can then augment this simple transformation.
The identity transformation style sheet looks like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"> <!-- Identity transformation template --> <xsl:template> <xsl:copy> <xsl:apply-templates select="@* | * | comment() | pi() | text()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
The <xsl:copy> element is the heart of this template, copying any type of node to the output:
Here's how the template uses <xsl:copy> to duplicate an entire tree:
Microsoft® Internet Explorer 5 uses white space in the style sheet to do some limited "pretty-printing" of the output. To prevent unwanted white space, it is best to remove it in the template by placing the identity transform style sheet on one line. Likewise, if you want to preserve white space from the source document, the source XML should specify xml:space="preserve". More information on controlling white space can be found in Controlling White Space.
Additional templates can be added to this style sheet to describe different processing for certain nodes. To filter out certain "stock" elements in the previous "portfolio" XML data, just add a template that suppresses them. Each time a stock node with a price greater than 50 is encountered during the identity transformation, no output will be generatedand since there is no <xsl:apply-templates>, so will all its children.
<xsl:template match="stock[price $gt$ 50]" />
Similarly, to sort the remaining stock elements, you could add another template. In the case of sorting, you must invoke the template on the parent of the items to be sorted. The first <xsl:apply-templates> element causes all the attributes to be copied first, since sorting the attributes doesn't make a lot of sense.
<xsl:template match="portfolio"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:apply-templates select="stock" order-by="price"/> </xsl:copy> </xsl:template>
The final style sheet copies a portfolio document, filters out any stock elements not on the NASDAQ stock exchange, and sorts the remaining ones by price.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"> <!-- Identity transformation template --> <xsl:template> <xsl:copy> <xsl:apply-templates select="@* | * | comment() | pi() | text()"/> </xsl:copy> </xsl:template> <!-- Filter out stocks not listed on the nasdaq stock exchange --> <xsl:template match="stock[@exchange != 'nasdaq']" /> <!-- Sort stocks by price --> <xsl:template match="portfolio"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:apply-templates select="stock" order-by="price"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
Notice that the identity transform template must come first, or it will prevent the other templates from being checked.
Try it! You can see this transformation at XML Sorting Demo.