2010-11-10 87 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