c# - 使用 LINQ 对 XML 进行排序

标签 c# xml linq sorting

我想用 LINQ 对 XML 文件进行排序。 XML 如下,只是一个示例。通常它更大更复杂。 XML 应按标题升序排序。不是一次整个 XML,而是每个 parentNode 本身。叶子总是在底部。文件夹或非叶子在顶部。以下 XML 的结构已经很好,但标题顺序错误。排序算法还应该替换错误定位的非叶节点。 我已经有一些代码可以完成这项工作,但我想知道是否有更优雅或更短的方法。目前我必须递归调用一个函数来进行遍历。也许这可以用另一种方式来完成。 谢谢。

雷内

这是我的 XML:

<Node title="text99" leaf="no">
<Node title="text98" leaf="no">
    <Node title="text97" leaf="no">
        <Node title="text96" leaf="yes"/>
        <Node title="text95" leaf="yes"/>
    </Node>
    <Node title="text94" leaf="no">
        <Node title="text93" leaf="yes"/>
        <Node title="text92" leaf="yes"/>
    </Node>
    <Node title="text91" leaf="yes"/>
    <Node title="text90" leaf="yes"/>
</Node>
<Node title="text89" leaf="no">
    <Node title="text88" leaf="no">
        <Node title="text87" leaf="yes"/>
        <Node title="text86" leaf="yes"/>
    </Node>
    <Node title="text85" leaf="no">
        <Node title="text84" leaf="yes"/>
        <Node title="text83" leaf="yes"/>
    </Node>
    <Node title="text82" leaf="yes"/>
    <Node title="text81" leaf="yes"/>
</Node>
<Node title="text80" leaf="no">
    <Node title="text79" leaf="no">
        <Node title="text78" leaf="no">
            <Node title="text78" leaf="yes"/>
            <Node title="text77" leaf="yes"/>
        </Node>
        <Node title="text76" leaf="no">
            <Node title="text75" leaf="yes"/>
            <Node title="text74" leaf="yes"/>
        </Node>
        <Node title="text73" leaf="yes"/>
        <Node title="text72" leaf="yes"/>
    </Node>
    <Node title="text71" leaf="no">
        <Node title="text70" leaf="no">
            <Node title="text69" leaf="yes"/>
            <Node title="text68" leaf="yes"/>
        </Node>
        <Node title="text67" leaf="no">
            <Node title="text66" leaf="yes"/>
        </Node>
        <Node title="text65" leaf="yes"/>
        <Node title="text64" leaf="yes"/>
    </Node>
    <Node title="text63" leaf="yes"/>
    <Node title="text62" leaf="yes"/>
</Node>
<Node title="text61" leaf="yes"/>
<Node title="text60" leaf="yes"/>

这是我的代码:

using (XmlReader reader = XmlReader.Create(XmlStream))
{
    XDocument xDoc = XDocument.Load(reader);                        
    Action<XElement> sortXml = null;
    sortXml = xElement =>
    {
    bool sortParentNode = false;
    foreach (var xElem in xElement.Elements())
    {                                    
        if (xElem.HasElements)
        {
            // go into deep
                sortXml(xElem);
        }
        else
            {
        // break loop and sort parentNode
        sortParentNode = true;
        break;
        }                                    
    }
    if (sortParentNode)
    {
        xElement.ReplaceNodes(from node in xElement.Elements()
                orderby node.Attribute("title").Value
                group node by node.HasElements into folderGroup
                orderby folderGroup.Key descending
                select folderGroup);
    }
};
sortXml(xDoc.Root);                        
}

最佳答案

The XML should be sorted by title, ascending. Not the whole XML at once, but every parentNode for itself. Leafs are always at the bottom. Folder or non-leafs are at the top.

这个解决方案似乎符合您的要求:

public static void SortXml(XElement node)
{
    node.ReplaceNodes(node.Elements("Node")
        .OrderBy(x => (string)x.Attribute("leaf"))
        .ThenBy(x => (string)x.Attribute("title")));

    foreach (var childNode in node.Elements("Node"))
        SortXml(childNode);
}

...

XDocument doc = XDocument.Load("test.xml");
SortXml(doc.Root);

所有子节点首先按叶属性的值排序(使用按字母顺序“否”出现在"is"之前的事实),然后按标题排序。所有一级子节点都以这种方式排序,然后使用这些子节点中的每一个作为输入递归重复。

输出:

<Node title="text99" leaf="no">
  <Node title="text80" leaf="no">
    <Node title="text71" leaf="no">
      <Node title="text67" leaf="no">
        <Node title="text66" leaf="yes" />
      </Node>
      <Node title="text70" leaf="no">
        <Node title="text68" leaf="yes" />
        <Node title="text69" leaf="yes" />
      </Node>
      <Node title="text64" leaf="yes" />
      <Node title="text65" leaf="yes" />
    </Node>
    <Node title="text79" leaf="no">
      <Node title="text76" leaf="no">
        <Node title="text74" leaf="yes" />
        <Node title="text75" leaf="yes" />
      </Node>
      <Node title="text78" leaf="no">
        <Node title="text77" leaf="yes" />
        <Node title="text78" leaf="yes" />
      </Node>
      <Node title="text72" leaf="yes" />
      <Node title="text73" leaf="yes" />
    </Node>
    <Node title="text62" leaf="yes" />
    <Node title="text63" leaf="yes" />
  </Node>
  <Node title="text89" leaf="no">
    <Node title="text85" leaf="no">
      <Node title="text83" leaf="yes" />
      <Node title="text84" leaf="yes" />
    </Node>
    <Node title="text88" leaf="no">
      <Node title="text86" leaf="yes" />
      <Node title="text87" leaf="yes" />
    </Node>
    <Node title="text81" leaf="yes" />
    <Node title="text82" leaf="yes" />
  </Node>
  <Node title="text98" leaf="no">
    <Node title="text94" leaf="no">
      <Node title="text92" leaf="yes" />
      <Node title="text93" leaf="yes" />
    </Node>
    <Node title="text97" leaf="no">
      <Node title="text95" leaf="yes" />
      <Node title="text96" leaf="yes" />
    </Node>
    <Node title="text90" leaf="yes" />
    <Node title="text91" leaf="yes" />
  </Node>
  <Node title="text60" leaf="yes" />
  <Node title="text61" leaf="yes" />
</Node>

关于c# - 使用 LINQ 对 XML 进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5451987/

相关文章:

c# - 复制列表中的更改

c# - 在 propertygrid 中使用 datetimepicker 选择时间

java - Android Studio : Using radioButtons for a quiz

sql-server - 如何在 SQL Server 2012 中从 XML 层次结构的下一级查询另一个属性?

c# - Entity Framework Core 比较两个子集合属性

javascript - 为什么 Underscore.js chain() 方法不是惰性的?

c# - 通知线程停止的选项

c# - 在 foreach 循环中启动一个新线程

javascript - xml 不是一个函数

c# - 如何使我的多对多查询更快?