【问题标题】:sort problem with <xsl:sort ...> in .NET 4.NET 4 中 <xsl:sort ...> 的排序问题
【发布时间】:2011-06-24 08:25:27
【问题描述】:

当我使用 .NET 4 作为目标框架编译我的程序时遇到问题。排序不起作用。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Xsl;

namespace ExampleSortProblemServer
{
  class Program
  {
    static void Main(string[] args)
    {
        // argument is the filename
        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.Load(args[0]);

        XslCompiledTransform xslt = new XslCompiledTransform();
        XmlResourceResolver resolver = new XmlResourceResolver(typeof (IReport));
        xslt.Load(args[1]);

        String foStr = CreateFO(xmlDocument, xslt, resolver);

        Console.WriteLine(foStr);
    }

    public static string CreateFO(XmlNode doc, XslCompiledTransform xslt, XmlResolver resolver)
    {
        string fo;

        using (var stringReader = new StringReader(doc.OuterXml))
        {
            using (var xmlTextReader = new XmlTextReader(stringReader))
            {
                using (var stringWriter = new StringWriter())
                {
                    using (var xmlTextWriter = new XmlTextWriter(stringWriter))
                    {
                        try
                        {
                            xslt.Transform(xmlTextReader, null, xmlTextWriter, resolver);
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                            throw;
                        }
                        stringWriter.Flush();
                        fo = stringWriter.ToString();
                    }
                }
            }
        }
        return fo;
    }
  }
}

数据是“Datan.xml”:

<daten>
<employees>
    <name>Knight</name>
    <name>Cook</name>
    <name>Superman</name>
    <name>Yoda</name>
    <name>Albright</name>
</employees>
</daten>

样式表是“Datan.xsl”:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:fo="http://www.w3.org/1999/XSL/Format">

<xsl:output method="xml" encoding="utf-8" indent="yes"/>

<xsl:template match="/">
    <xsl:variable name="daten" select="*[local-name()='daten']"/>
    <xsl:apply-templates select="$daten">
        <xsl:sort select="normalize-space(*[local-name()='employees']/*[local-name()='name']" order="ascending"/>
    </xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>

您可以使用以下方式调用该程序: ExampleSortProblemServer.exe Daten.xml Daten.xsl

预期的顺序应该是:

奥尔布赖特库克骑士超人尤达

知道什么是不正确的吗?

【问题讨论】:

  • 连续的using 声明不需要花括号;如果你省略除了最里面的对之外的所有代码,代码的可读性会更高(在这种情况下,标准缩进也不会缩进连续的使用。
  • 另外,XmlTextWriter 构造函数已被弃用,取而代之的是 XmlWriter.Create
  • 最后,最好不要在辅助方法中进行一般异常日志记录;最好尽可能在全球范围内这样做。只捕获您可以实际修复的异常。
  • 可读性取决于个人...解决问题的提示将不胜感激。

标签: .net xml xslt c#-4.0 xsl-fo


【解决方案1】:

我认为这是因为您尝试排序 daten 而不是 names。

例如,这个样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/">
    <xsl:apply-templates select="*[local-name()='daten']/*[local-name()='employees']/*[local-name()='name']">
      <xsl:sort order="ascending"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="name">
    <xsl:apply-templates/>
    <xsl:text> </xsl:text>
  </xsl:template>

</xsl:stylesheet>

输入“Datan.xml”:

<daten>
  <employees>
    <name>Knight</name>
    <name>Cook</name>
    <name>Superman</name>
    <name>Yoda</name>
    <name>Albright</name>
  </employees>
</daten>

产生这个输出:

Albright Cook Knight Superman Yoda

编辑

样式表只需稍作更新即可处理您作为答案添加的 XML 输入。

这个输入:

<daten>
  <employees>
    <employee>
      <name>Knight</name>
      <forename>Peter</forename>
    </employee>
    <employee>
      <name>Knight</name>
      <forename>Gilbert</forename>
    </employee>     
    <employee>
      <name>Cook</name>
      <forename>Thomas</forename>
    </employee>
    <employee>
      <name>Cook</name>
      <forename>Charles</forename>
    </employee>     
    <employee>
      <name>Superman</name>
      <forename>Kal-El</forename>
    </employee>
    <employee>
      <name>Yoda</name>
      <forename></forename>
    </employee>
    <employee>
      <name>Albright</name>
      <forename>Peter</forename>
    </employee>
    <employee>
      <name>Albright</name>
      <forename>Charles</forename>
    </employee> 
    <employee>
      <name>Albright</name>
      <forename>Mark</forename>
    </employee>     
  </employees>
</daten>

使用更新的样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/">
    <xsl:apply-templates select="*[local-name()='daten']/*[local-name()='employees']/*[local-name()='employee']">
      <xsl:sort order="ascending" select="name"/>
      <xsl:sort order="ascending" select="forename"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="name">
    <xsl:apply-templates/>
    <xsl:text> </xsl:text>
  </xsl:template>

  <xsl:template match="forename">
    <xsl:apply-templates/>
    <xsl:text>&#xA;</xsl:text>
  </xsl:template>

</xsl:stylesheet>

产生你想要的输出:

Albright Charles
Albright Mark
Albright Peter
Cook Charles
Cook Thomas
Knight Gilbert
Knight Peter
Superman Kal-El
Yoda 

【讨论】:

  • 到目前为止这似乎有效。 但是: 1. 输出应该没有“名称”标签:
    Albright
    Cook
    Knight
    Superman
    Yoda
    2. 会是什么如果我有几个排序级别的解决方案?例如。 1. 级别:名称 2. 级别:forname ... 所以得到如下结果:
    Albright Mark
    Albright Peter
    Cook Charles
    Cook Thomas
    ...
  • 1.样式表的第一个版本只是为了演示正确的排序(让您开始)。我对其进行了修改,以便您获得所需的输出。 (我添加了一个模板来匹配name。) 2. 您能否添加另一个示例 XML 实例,以便我可以看到您所描述的名称/名称?
  • @jahuer1 - 请查看我的编辑,获取稍加修改的样式表,生成您想要的输出。
  • @DevNull 清洁解决方案 +1。也许,您可以省略order,因为“升序”是默认设置,并且使用self::xxx 代替self::xxx。
  • 好建议@empo。我留下了order,以便 OP 可以看到如何轻松更改订单(不问其他问题)。我还在样式表中留下了local-name(),因为那是 OP 在他/她的样式表中的内容。我更喜欢self::xxx。它干净了很多。我也喜欢你对另一个“答案”的尤达评论。 :-)
【解决方案2】:

这里是一个扩展的 xml 文件:

<daten>
<employees>
    <employee>
        <name>Knight</name>
        <forename>Peter</forename>
    </employee>
    <employee>
        <name>Knight</name>
        <forename>Gilbert</forename>
    </employee>     
    <employee>
        <name>Cook</name>
        <forename>Thomas</forename>
    </employee>
    <employee>
        <name>Cook</name>
        <forename>Charles</forename>
    </employee>     
    <employee>
        <name>Superman</name>
        <forename>Kal-El</forename>
    </employee>
    <employee>
        <name>Yoda</name>
        <forename></forename>
    </employee>
    <employee>
        <name>Albright</name>
        <forename>Peter</forename>
    </employee>
    <employee>
        <name>Albright</name>
        <forename>Charles</forename>
    </employee> 
    <employee>
        <name>Albright</name>
        <forename>Mark</forename>
    </employee>     
</employees>
</daten>

结果应该是:

奥尔布赖特查尔斯
奥尔布赖特马克
奥尔布赖特彼得
库克查尔斯
库克托马斯
骑士吉尔伯特
骑士彼得
超人卡尔-艾尔
尤达

【讨论】:

  • 我想要一位名叫 Yoda 的同事。
猜你喜欢
  • 1970-01-01
  • 2012-09-09
  • 2018-12-04
  • 1970-01-01
  • 2012-03-25
  • 2018-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多