【问题标题】:Sorting all the elements in a XDocument对 XDocument 中的所有元素进行排序
【发布时间】:2011-03-29 00:59:53
【问题描述】:

我有一个 XDocument,我想在其中按字母顺序对所有元素进行排序。这是结构的简化版本:

<Config>
 <Server>
    <Id>svr1</Id>
    <Routing>
        <RoutingNodeName>route1</RoutingNodeName>
        <Subscription>
            <Id>1</Id>
        </Subscription>
        <RoutingParameters id="Routing1">
            <Timeout>7200</Timeout>
        </RoutingParameters>
    </Routing>
    <Storage>
            <Physical>HD1</Physical>
    </Storage>
 </Server>
 <Applications>
    <Services>
        <Local></Local>
    </Services>
 </Applications>
</Config>

我想对这个文档中的各个级别的元素进行排序,到目前为止我可以这样排序:

private static XDocument Sort(XDocument file)
{
    return new XDocument(
        new XElement(file.Root.Name,
            from el in file.Root.Elements()
            orderby el.Name.ToString()
            select el));
}

产生:

<Config>
<Applications>
  <Services>
    <Local></Local>
  </Services>
</Applications>
<Server>
  <Id>svr1</Id>
  <Routing>
    <RoutingNodeName>route1</RoutingNodeName>
    <Subscription>
      <Id>1</Id>
    </Subscription>
    <RoutingParameters id="Routing1">
      <Timeout>7200</Timeout>
    </RoutingParameters>
  </Routing>
  <Storage>
    <Physical>HD1</Physical>
  </Storage>
</Server>
</Config>

我希望能够以相同的方式对所有子元素进行排序(理想情况下通过递归函数)。有什么想法可以通过 LINQ 实现吗?

感谢您的任何想法。

【问题讨论】:

    标签: c# sorting linq-to-xml


    【解决方案1】:

    您已经有了对元素进行排序的方法。只需递归应用它:

    private static XElement Sort(XElement element)
    {
        return new XElement(element.Name,
                from child in element.Elements()
                orderby child.Name.ToString()
                select Sort(child));
    }
    
    private static XDocument Sort(XDocument file)
    {
        return new XDocument(Sort(file.Root));
    }
    

    请注意,这会从您的文档中删除所有非元素节点(属性、文本、cmets 等)。


    如果要保留非元素节点,则必须将它们复制过来:

    private static XElement Sort(XElement element)
    {
        return new XElement(element.Name,
                element.Attributes(),
                from child in element.Nodes()
                where child.NodeType != XmlNodeType.Element
                select child,
                from child in element.Elements()
                orderby child.Name.ToString()
                select Sort(child));
    }
    
    private static XDocument Sort(XDocument file)
    {
        return new XDocument(
                file.Declaration,
                from child in file.Nodes()
                where child.NodeType != XmlNodeType.Element
                select child,
                Sort(file.Root));
    }
    

    【讨论】:

    • 谢谢,我能够使用它来获得我想要的属性和文本结果。干杯。
    • 这是展示如何对节点进行排序的好方法,但摆脱所有值和属性并不是回答 OP 问题的答案。 @ZeroCool 如果您编辑此答案,向其他人展示您如何获得所需的正确答案,那就太好了。
    • @ArvoBowen 很抱歉没有为我的最终解决方案提供更新,我没有那个代码库了,所以我无法查看我最终做了什么,但我认为它类似于您和 dtb 已添加。感谢您添加您的 cmets 和答案。很高兴你能解决它。
    • 谢谢! +1 来自我 ;)
    【解决方案2】:

    此方法对真实文档进行扩展并保留属性和文本值

    我根据一些不同的帖子和代码从这里和那里想出了这个...感谢所有贡献的人!

    在同一个命名空间内(不是同一个类)添加以下...

    public static void Sort(this XElement source, bool bSortAttributes = true)
    {
        //Make sure there is a valid source
        if (source == null) throw new ArgumentNullException("source");
    
        //Sort attributes if needed
        if (bSortAttributes)
        {
            List<XAttribute> sortedAttributes = source.Attributes().OrderBy(a => a.ToString()).ToList();
            sortedAttributes.ForEach(a => a.Remove());
            sortedAttributes.ForEach(a => source.Add(a));
        }
    
        //Sort the children IF any exist
        List<XElement> sortedChildren = source.Elements().OrderBy(e => e.Name.ToString()).ToList();
        if (source.HasElements)
        {
            source.RemoveNodes();
            sortedChildren.ForEach(c => c.Sort(bSortAttributes));
            sortedChildren.ForEach(c => source.Add(c));
        }
    }
    

    要使用文档扩展名...

    //Load the xDoc
    XDocument xDoc = XDocument.Load("c:\test.xml");
    
    //Sort the root element
    xDoc.Root.Sort();
    

    【讨论】:

    • 将一行改为: List sortedChildren = source.Elements().OrderBy(elem => elem.Attributes("Name").Any() ? elem.Attributes("Name" ).First().Value.ToString() : string.Empty).ToList();对 edmx 文件进行排序非常有用。谢谢阿沃
    【解决方案3】:

    这是一个更新的示例,它将在执行排序时包含所有属性。

    private static XElement Sort(XElement element)
    {
        XElement newElement = new XElement(element.Name,
            from child in element.Elements()
            orderby child.Name.ToString()
            select Sort(child));
        if (element.HasAttributes)
        {
            foreach (XAttribute attrib in element.Attributes())
            {
                newElement.SetAttributeValue(attrib.Name, attrib.Value);
            }
        }
        return newElement;
    }
    
    private static XDocument Sort(XDocument file)
    {
        return new XDocument(Sort(file.Root));
    }
    

    这篇文章对我帮助很大,因为我不想使用 XSLT 执行 XML 排序,因为我不想重新格式化 XML。我到处寻找一个简单的解决方案来使用 C# 和 ASP.NET 执行 XML 排序,当我找到这个线程时我很高兴。感谢所有人,这正是我所需要的。

    【讨论】:

    • 这不会完成 OP 想要的。这将删除所有值!
    【解决方案4】:

    我认为这些扩展方法效果最好。

    public static class XmlLinq
    {
      public static void Sort(this XElement source, bool sortAttributes = true)
      {
         if (source == null)
            throw new ArgumentNullException("source");
    
         if (sortAttributes)
            source.SortAttributes();
    
         List<XElement> sortedChildren = source.Elements().OrderBy(e => e.Name.ToString()).ToList();
         source.RemoveNodes();
    
         sortedChildren.ForEach(c => source.Add(c));
         sortedChildren.ForEach(c => c.Sort());
      }
    
      public static void SortAttributes(this XElement source)
      {
         if (source == null)
            throw new ArgumentNullException("source");
    
         List<XAttribute> sortedAttributes = source.Attributes().OrderBy(a => a.ToString()).ToList();
         sortedAttributes.ForEach(a => a.Remove());
         sortedAttributes.ForEach(a => source.Add(a));
      }
    }
    

    【讨论】:

    • 这对我来说是一个很好的基础,但它并没有保留所有的文本值或属性。所以我不得不添加我自己的答案,并做了一些修改。 ;)
    猜你喜欢
    • 1970-01-01
    • 2013-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多