This question already has an answer here:
-
XSLT to order attributes
2 answers
I have HTML in XML format which I am parsing using XSLT. My HTML looks like this:
<html>
<head>
<meta charset="utf-8" />
<title>Test</title>
</head>
<body>
<img height="" width="' src="google.gif?<>" />
</body>
</html>
After XSLT parsing it looks like this:
<html>
<head>
<meta charset="utf-8" />
<title>Test</title>
</head>
<body>
<img height="" src="google.gif?<>" width=""/>
</body>
</html>
I want @src
as last attribute like <img height="" width="" src="google.gif?<>" />
, but by default attributes are sorted in alphabetical order. I am not able to do it using <xsl:sort>
.
XSLT produces as output a result tree conforming to the XDM data model, and in the XDM model, attributes are unordered. Since they have no order, it follows that XSLT stylesheet instructions cannot control the order.
The only opportunity for controlling the order arises during serialization, when the unordered attribute nodes in the result tree are converted to an ordered sequence of name="value" pairs in the lexical XML output. The standard serialization properties available in XSLT (any version) do not provide any way of controlling this. Saxon however has an extension attribute saxon:attribute-order
- see
http://www.saxonica.com/documentation/index.html#!extensions/output-extras/serialization-parameters
In addition to <img height="" width="' src="google.gif?<>" />
not being well-formed as commented by Martin Honnen...
Attribute order is insignificant per the XML Recommendation:
Note that the order of attribute specifications in a start-tag or
empty-element tag is not significant.
Therefore, XSLT provides no way to constrain attribute ordering.
If you refuse to embrace this recommendation to ignore ordering for attributes, see Martin Honnen's suggestions regarding how to control attribute ordering output to an earlier question on XSLT attribute ordering.
Input HTML (with wellformation):
<html>
<head>
<meta charset="utf-8" />
<title>Test</title>
</head>
<body>
<img height="13" width="12" src="google.gif?" id="id1"/>
</body>
</html>
XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
</xsl:template>
<xsl:template match="img">
<xsl:copy>
<xsl:for-each select="@*[not(name()='src')]">
<xsl:sort select="name()"/>
<xsl:attribute name="{name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates select="@*[name()='src']"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result:
<html>
<head>
<meta charset="utf-8"/>
<title>Test</title>
</head>
<body>
<img height="13" id="id1" width="12" src="google.gif?"/>
</body>
</html>