我在尝试使用 CLR4.0 中的 XslCompiledTransform 对 XSL 文件进行排序时遇到问题。这是我的示例 XML 文件(注意:第二个 <foo>
元素后有一个空格):
<?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>
当我应用以下 XSL 文件时:
<?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>
我得到以下结果:
<html>
<body>
<table>
<tr>
<td>B</td>
</tr>
<tr>
<td>A</td>
</tr>
</table>
</body>
</html>
但是,如果我删除第二个 <foo>
之后的空格元素,结果文件被正确排序。这看起来可能是 XslCompiledTransform 中的错误,但我希望有人可以提供解决方法。
编辑:如果有人在重现它时遇到问题,这是我正在使用的代码:
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);
}
}
最佳答案
令人怀疑的是,如果将每个 api
元素的 XML 修改为以下内容,结果将按预期排序:
<api id="apiId">
<id>apiId</id>
<foos>
<foo />
</foo>
</api>
此外,如果 a) 每个 api
元素的 XML 被修改以完全删除 id
属性
<api>
<id>apiId</id>
<foos>
<foo />
</foo>
</api>
和 b) 只有 XSL 文件中对 @id
的 second 引用更改为 id
,结果仍将按字母顺序排序!
XslCompiledTransform
可能试图对名为 id
的子元素而不是名为 id
的属性进行排序,或者这可能只是运气不好。无论哪种方式,我都已验证它愿意对名为 id
的子元素进行正确排序。
考虑到这一点,我可以想到两种解决方法,但这两种方法都需要您对转换过程有一定程度的控制。
方法 1:您可以更改 XML
更改编写原始 XML 的过程,以将 id
指定为 api
元素包含的第一个元素。然后更新 XSL 以将对 @id
的引用替换为 id
。
方法 2:您可以在应用 XSL 之前预处理 XML
使用 XSL 转换将 id
属性的值移动到 api
的子元素中,然后应用与方法 1 中相同的 XSL 到中间 XML 文档。在处理大型 XML 文件时,将文档转换两次显然不太理想。
以下 XSL 将使您从原始 XML 到中间 XML:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.1">
<!-- recursively copy each element (including root) -->
<xsl:template match="*|/">
<xsl:copy>
<!-- xsl:copy ignores attributes, copy those as well -->
<xsl:copy-of select="@*"/>
<!-- continue to deep copy the element -->
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<!-- for api elements, move the id attribute into an element -->
<xsl:template match="api">
<api>
<id>
<xsl:value-of select="@id"/>
</id>
<!-- continue deep copy of api element contents -->
<xsl:apply-templates />
</api>
</xsl:template>
</xsl:stylesheet>
希望对您有所帮助!
关于.net - XSL 排序问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4140360/