3

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

<?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

4 回答 4

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) 只有XSL 文件中的第二个引用更改为,结果仍将按字母顺序排序! @idid


可能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>

我希望这有帮助!

于 2010-11-10T01:56:46.317 回答
2

如果将样式表版本更改为任何> = 2.0的'1.0',它就可以工作

于 2010-12-29T08:33:06.223 回答
1

我没有尝试重现该问题,并且我没有看到您的 XSL 有任何明显错误。以下是我将探索的内容,看看这是您的问题还是 XSL 引擎中的错误:尝试删除后面的空格<foo>并将 id "A" 更改为 "C"。您是否按“B”、“C”的顺序获得输出?换句话说,确保它实际上是按 id 排序的。

于 2010-11-10T01:25:45.887 回答
0

@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>如果您按元素排序,那么哪个是正确的排序

于 2010-11-15T18:16:04.460 回答