I'm trying to canonicalize the representation of some XML data by sorting each element's attributes by name (not value). The idea is to keep textual differences minimal when attributes are added or removed and to prevent different editors from introducing equivalent variants. These XML files are under source control and developers are wanting to diff the changes without resorting to specialized XML tools.
I was surprised to not find an XSL example of how to this. Basically I want just the identity transform with sorted attributes. I came up with the following with seems to work in all my test cases:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="*|/|text()|comment()|processing-instruction()">
<xsl:copy>
<xsl:for-each select="@*">
<xsl:sort select="name(.)"/>
<xsl:copy/>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
As a total XSL n00b I would appreciate any comments on style or efficiency. I thought it might be helpful to post it here since it seems to be at least not a common example.
XSLT's xsl:sort instruction lets you sort a group of similar elements. Attributes for this element let you add details about how you want the sort done -- for example, you can sort using alphabetic or numeric ordering, sort on multiple keys, and reverse the sort order.
XSL Transformation (XSLT)XSLT is designed to be used as part of XSL. In addition to XSLT, XSL includes an XML vocabulary for specifying formatting. XSL specifies the styling of an XML document by using XSLT to describe how the document is transformed into another XML document that uses the formatting vocabulary.
Incorporating <STYLE> Elements into an XSLT FileAn XSLT style sheet can emit HTML <STYLE> elements, including CSS specifications, directly into the HTML that results from the XSLT transformation. This option works best when the number of CSS rules is small and easily managed.
With xslt being a functional language doing a for-each might often be the easiest path for us humans but not the most efficient for XSLT processors since they cannot fully optimize the call.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*">
<xsl:sort select="name()"/>
</xsl:apply-templates>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|comment()|processing-instruction()">
<xsl:copy />
</xsl:template>
</xsl:stylesheet>
This is totally trivial in this regards though and as a "XSL n00b" i think you solved the problem very well indeed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With