我遇到了一个问题,试图使用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);
    }
}
有帮助吗?

解决方案 4

@Russ Ferri,感谢您的回答。它指向我的方向正确。 XSLCompileDTransform中似乎是错误的是,当您要按元素的属性进行排序时,它实际上按照该元素的第一个子元素的值进行分类。因此,正如Russ所指出的那样,这将与我的原始转换文件正确排序:

<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> 元素

其他提示

可疑的,如果每个XML api 元素已修改为以下内容,结果将按预期进行排序:

<api id="apiId">
   <id>apiId</id>
   <foos>
      <foo />
   </foo>       
</api>

此外,如果a)每个 api 修改元素以删除 id 完全属性

<api>
   <id>apiId</id>
   <foos>
      <foo />
   </foo>       
</api>

b)只有 第二 引用 @id 在XSL中,文件已更改为 id, ,结果仍将按字母顺序排序!


可能 XslCompiledTransform 正在尝试分类一个名为的子元素 id 而不是命名的属性 id, ,否则这可能只是愚蠢的运气。无论哪种方式,我都验证了它愿意在名为的子元素上正确排序 id.

考虑到这一点,我可以想到两个解决方法,但两者都要求您对转换过程有一定程度的控制。

方法1:您能够更改XML

更改编写原始XML的过程以指定 id 作为第一个元素包含 api 元素。然后更新XSL以替换引用到 @idid.

方法2:在应用XSL之前,您可以预处理XML

使用XSL变换移动 id 将属性归因于子元素 api, ,然后应用与您中相同的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>

我希望这有帮助!

如果将sytyle表版本更改为任何> = 2.0的'1.0',它有效

我没有试图重现问题,而且您的XSL显然没有任何错误。这是我要探索的内容,看看是您的问题还是XSL引擎中的错误:尝试删除空间 <foo> 并将ID“ A”更改为“ C”。您是否以“ B”,“ C”顺序获得输出?换句话说,请确保它实际上是按ID进行排序。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top