2010-11-10 39 views
3

我在使用CLR4.0中的XslCompiledTransform对XSL文件进行排序时遇到问题。这里是我的示例XML文件(注:有第二<foo>元素之后有一个空格):XSL排序的问题

<?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); 
    } 
} 
+0

这个问题似乎是不可重现排序(测试用MSXSL 4和3)。 **如果**在'XslCompiledTransform'中有一个错误,这应该是一个'xsltprocessor'标记的问题。 – 2010-11-10 16:50:24

+0

如果有人想跟踪它,我也将它提交给微软。我用稍微不同的文件内容,但结果是一样的:https://connect.microsoft.com/VisualStudio/feedback/details/620628/problem-with-xsl-sort-nodes-when-using-xslcompiledtransform – 2010-11-10 22:56:07

+0

我试过了很难和*不能重现*它。 ! – 2010-11-12 02:59:35

回答

0

@Russ Ferri,谢谢你的回答。它指出我在正确的方向。看起来XslCompiledTransform中的错误是,当你想按元素的属性进行排序时,它实际上按该元素的第一个子元素的值进行排序。因此,作为拉斯指出,这将排序正确地与我原来的转换文件:

<reflection> 
    <apis> 
    <api id="C"> 
     <id>C</id> 
     <foos> 
     <foo/> 
     </foos> 
    </api> 
    <api id="B"> 
     <id>B</id> 
     <foos> 
     <foo/> 
     </foos> 
    </api> 
    </apis> 
</reflection> 

但这不是这样的:

<reflection> 
    <apis> 
    <api id="C"> 
     <anyElementName>C</anyElementName> 
     <foos> 
     <foo/> 
     </foos> 
    </api> 
    <api id="B"> 
     <anyElementName>B</anyElementName> 
     <foos> 
     <foo/> 
     </foos> 
    </api> 
    </apis> 
</reflection> 

事实上,属性名完全被忽略,所以如果我运行东西变换是这样的:

<reflection> 
    <apis> 
    <api id="C"> 
     <anyElementName>Z</anyElementName> 
     <foos> 
     <foo/> 
     </foos> 
    </api> 
    <api id="A"> 
     <anyElementName>Y</anyElementName> 
     <foos> 
     <foo/> 
     </foos> 
    </api> 
    <api id="B"> 
     <anyElementName>X</anyElementName> 
     <foos> 
     <foo/> 
     </foos> 
    </api> 
    </apis> 
</reflection> 

结果看起来是这样的:

<html> 
    <body> 
    <table> 
     <tr> 
     <td>B</td> 
     </tr> 
     <tr> 
     <td>A</td> 
     </tr> 
     <tr> 
     <td>C</td> 
     </tr> 
    </table> 
    </body> 
</html> 

这是正确的排序,如果你是由<anyElementName>元素

1

我没有试图重现的问题,我没有看到任何明显的错误你XSL。以下是我将探讨的问题,看看它是否是您的问题或XSL引擎中的错误:尝试删除<foo>后的空格,并将ID“A”更改为“C”。你是否按照“B”,“C”的顺序输出?换句话说,确保它实际上是通过ID排序的。

+0

好问题。他们应该作为评论提交,而不是答案。 – 2010-11-10 01:27:16

+1

感谢您的反馈,@Mads。我将其作为如何调试问题的建议进行了修改。 – 2010-11-10 01:37:11

+0

当我将“A”更改为“C”时,排序顺序出现正确,空间不正确且没有空格,所以它确实没有意义。 – 2010-11-10 15:47:02

2

可疑,如果对于每个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)只在参照@id在XSL文件被改变为id,结果仍然按字母顺序排序!


这是可能的XslCompiledTransform试图排序命名id的不是命名id属性的子元素,或者这可能仅仅是偶然的运气。无论哪种方式,我已经验证它愿意在名为id的子元素上正确排序。请记住,我可以考虑两种解决方法,但都要求您对转换过程有一定程度的控制权。

方法1:您可以更改XML

变化过程编写原始的XML指定id由一个api元素包含的第一个元素。然后更新XSL以用id替代对@id的引用。

方法二:您可以将您的XSL

使用XSL转换到id属性的值迁入api子元素之前,预先处理XML,然后采用相同的XSL就像你在方法1中的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> 

我希望这有助于!

+0

它看起来像它的工作,但实际上,它是防止所有排序。当我将“A”更改为“C”(将初始元素置于未排序的顺序)并删除空格时,结果文件从未改变其顺序,包括空格或空格。 – 2010-11-10 15:50:11

+0

你是对的,对不起。我会稍微更新一下这个答案,其中包含一些我在多玩这个问题后注意到的一些事情。 – 2010-11-10 22:09:24

2

如果sytyle片版本更改为“1.0”的东西它的工作原理> = 2.0