I am having a problem trying to sort with an XSL file using the XslCompiledTransform in CLR4.0. Here is my sample XML file (Note: there is a space after the second <foo> element):
<?xml version="1.0" encoding="utf-8"?>
<reflection>
<apis>
<api id="A">
<foos>
<foo/>
</foos>
</api>
<api id="B">
<foos>
<foo/>
</foos>
</api>
</apis>
</reflection>
When I apply the following XSL file:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.1">
<xsl:template match="/">
<html>
<body>
<table>
<xsl:apply-templates select="/reflection/apis/api">
<xsl:sort select="@id" />
</xsl:apply-templates>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="api">
<tr>
<td>
<xsl:value-of select="@id" />
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
I get the following result:
<html>
<body>
<table>
<tr>
<td>B</td>
</tr>
<tr>
<td>A</td>
</tr>
</table>
</body>
</html>
However, if I remove the space after the second <foo> element, the resulting file is sorted correctly. This seems like it’s probably a bug in the XslCompiledTransform, but I was hoping someone might have a workaround.
Edit: If anyone is having trouble reproducing it, here is the code I am using:
XslCompiledTransform xslt = new XslCompiledTransform();
XsltSettings transformSettings = new XsltSettings(true, true);
xslt.Load("CreateVSToc.xsl", transformSettings, new XmlUrlResolver());
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.IgnoreWhitespace = true;
Stream readStream = File.Open("reflection.xml", FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
using (XmlReader reader = XmlReader.Create(readStream, readerSettings))
{
Stream outputStream = File.Open("toc.xml", FileMode.Create, FileAccess.Write, FileShare.Read | FileShare.Delete);
using (XmlWriter writer = XmlWriter.Create(outputStream, xslt.OutputSettings))
{
XsltArgumentList arguments = new XsltArgumentList();
xslt.Transform(reader, arguments, writer);
}
}
@Russ Ferri, thanks for your answer. It pointed me in the right direction. It appears the bug in the XslCompiledTransform is that when you want to sort by an attribute of an element, it actually sorts by the value of the first child element of that element. So as Russ pointed out, this will sort correctly with my original transform file:
But so will this:
In fact, the attribute name is completely ignored, so if I run the transform on something like this:
The result looks like this:
Which is the correct sorting if you were sorting by the
<anyElementName>elements