.net - XSL 排序问题

标签 .net xml xslt xslcompiledtransform

我在尝试使用 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 文件中对 @idsecond 引用更改为 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/

相关文章:

java - 如何使用apachecamel从soap响应中获取value值?

javascript - D3 将现有的 SVG 字符串(或元素)追加(插入)到 DIV

java - 使用 xpath 而不是 XSD 对象生成来访问 XML 详细信息?

xml - 我可以将 xslt 链接到另一个 xslt 吗?

c# - 解析维基词典

.net - 正则表达式,以字母/_开头的字符串,以及(可能)字母/数字/_之后的字符串

c# - 服务器上的 MVC 3 应用程序总是出现 500 错误

xml - 格式化具有指定小数位数的 double 值

xslt - 表行上是否有替代 "keep-together=' always'"的替代方法?

mysql - .net 异常 已经有一个与此连接关联的打开的 DataReader,必须先将其关闭