Сортировка XML с помощью LINQ - PullRequest
3 голосов
/ 28 марта 2011

Я хочу отсортировать файл XML с помощью LINQ. XML приведен ниже и является только примером. Обычно это намного больше и сложнее. XML должен быть отсортирован по заголовку по возрастанию. Не весь XML сразу, но каждый parentNode для себя. Листья всегда внизу. Папка или лист не наверху. Следующий XML уже хорошо структурирован, но заголовки расположены в неправильном порядке. Алгоритм сортировки также должен заменить неправильно расположенные неконечные узлы. У меня уже есть некоторый код, который делает эту работу, но я хочу знать, есть ли более элегантный или более короткий путь. На данный момент я должен вызвать рекурсивную функцию для выполнения обхода. Может быть, это можно сделать по-другому. Спасибо.

Rene

Вот мой 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);                        
}

1 Ответ

7 голосов
/ 28 марта 2011

XML должен быть отсортирован по заголовку, по возрастанию. Не весь XML сразу, но каждый parentNode для себя. Лифс всегда внизу. Папка или без листьев наверху.

Похоже, это решение соответствует вашим требованиям:

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);

Все дочерние узлы сортируются сначала по значению атрибута листа (использует тот факт, что «нет» предшествует «да» в алфавитном порядке), и по вторичному названию. Все дочерние узлы первого уровня сортируются таким образом, а затем рекурсивно повторяются с использованием каждого из этих дочерних узлов в качестве входных данных.

Выход:

<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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...