Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Сортировка XML


Автор: Vit 31.3.2008, 20:33
Требуется в общем-то тривиальная задача, но получающееся решение что-то меня не вдохновляет, какое-то некрасивое...



Требуется отсортировать сиблинги по значению атрибута. Поясню на примере

Итак есть XML типа
Код
<root>
  <child1 order="1">
    <subchildA order="1"/>
    <subchildB order="3"/>
    <subchildC order="2"/>
  </child1>
  <child2 order="3">
    <subchildD order="3"/>
    <subchildE order="1"/>
    <subchildF order="2"/>
  </child>
  <child3 order="2">
    <subchildG order="2"/>
    <subchildH order="3"/>
    <subchildJ order="1"/>
  </child3>
</root>


Из него надо получить XML в котором бы все сиблинги были отсортированы по значению аттрибута "Order", т.е. получить следующий результат:

Код
<root>
  <child1 order="1">
    <subchildA order="1"/>
    <subchildC order="2"/>
    <subchildB order="3"/>
  </child1>
  <child3 order="2">
    <subchildJ order="1"/>
    <subchildG order="2"/>
    <subchildH order="3"/>
  </child3>
  <child2 order="3">
    <subchildE order="1"/>
    <subchildF order="2"/>
    <subchildD order="3"/>
  </child>
</root>


Есть ли какое-то более или менее толковое решение?

Автор: Rififi 31.3.2008, 22:31
а нафига зачем нужна такая сортировка?

Автор: Vit 1.4.2008, 02:07
XML используется в третьестороннем приложении в качестве шаблона, приложение в соотвествии с ним строит GUI, к сожалению порядок имеет значение, так как элементы GUI должны следовать в порядке назначенном элементом Order, а не в порядке физического следования сиблингов.


 
Цитата(Rififi @  31.3.2008,  13:31 Найти цитируемый пост)
а нафига зачем нужна такая сортировка? 


 smile Всегда страшно бесили подобные вопросы! Неужели трудно ответить на поставленный вопрос, или понимание зачем оно мне нужно как то приблизят к его решению? 

В данном случае требуется из одного XML файла получить другой. И точка... Спорить зачем это кому-то надо не требуется... Типа если кому-то надо получить из файла png файл pcx можно до хрипоты доказывать что png во много раз лучше pcx... но задание то от этого не меняется!

Автор: Dblma 1.4.2008, 09:54
Я не подскажу конкретного решения, но могу предложить глянуть LINQ.

http://msdn2.microsoft.com/ru-ru/library/bb308960(en-us).aspx

Автор: mr.DUDA 1.4.2008, 10:28
Если делать руками, то так:
Код
using System;
using System.Xml;
using System.Collections.Generic;
using KVPair = System.Collections.Generic.KeyValuePair<int, int>;

class Program
{
    static void Main()
    {
        XmlDocument xml = new XmlDocument();
        xml.Load(@"c:\1.xml");
        SortNodesRecursive(xml, "order");
        xml.Save(@"c:\2.xml");
    }

    static void SortNodesRecursive(XmlNode startNode, string attributeName)
    {
        // получаем индексы узлов и значения сортируемого атрибута
        List<KVPair> attrToIndex = new List<KVPair>();
        List<XmlNode> originalNodeList = new List<XmlNode>();
        for (int i = 0; i < startNode.ChildNodes.Count; i++)
        {
            originalNodeList.Add(startNode.ChildNodes[i]);

            // получаем значение атрибута по которому сортируем, как int
            XmlAttribute attr = startNode.ChildNodes[i].Attributes[attributeName];
            if (attr != null)
            {
                int order;
                if (int.TryParse(attr.Value, out order))
                {
                    attrToIndex.Add(new KVPair(order, i));
                    continue;
                }
            }

            // не прокатило, добавляем с позицией "в самом низу"
            attrToIndex.Add(new KVPair(int.MaxValue, i));
        }

        // сортируем по атрибуту
        attrToIndex.Sort(delegate(KVPair x, KVPair y)
        {
            return x.Key.CompareTo(y.Key);
        });

        // перестраиваем список узлов
        foreach (XmlNode node in originalNodeList)
            startNode.RemoveChild(node);
        foreach (KVPair p in attrToIndex)
            startNode.AppendChild(originalNodeList[p.Value]);

        // выполняем то же рекурсивно
        foreach (XmlNode node in startNode.ChildNodes)
            SortNodesRecursive(node, attributeName);
    }
}


З.Ы. кстати твой XML невалидный, исправил:
Код
<root>
  <child1 order="1">
    <subchildA order="1"/>
    <subchildB order="3"/>
    <subchildC order="2"/>
  </child1>
  <child2 order="3">
    <subchildD order="3"/>
    <subchildE order="1"/>
    <subchildF order="2"/>
  </child2>
  <child3 order="2">
    <subchildG order="2"/>
    <subchildH order="3"/>
    <subchildJ order="1"/>
  </child3>
</root>

Автор: Rififi 1.4.2008, 12:08
Vit, 
Цитата
Всегда страшно бесили подобные вопросы

не волнуйся ты так, и береги нервы :gigi:

указанная задача решается с помощью .NET 3.5 и Linq to XML, или XSLT, или даже XQuery
первое проще всего, вот небольшой пример для подузла child1, остальное - по аналогии.

Код

XElement xdoc = XElement.Parse(
    @"<child1 order=""1"">
        <subchildA order=""1""/>
        <subchildB order=""3""/>
        <subchildC order=""2""/>
        </child1>"
    );


XElement sorted = new XElement("child1",
    from element in xdoc.Elements()
        orderby (string) element.Attribute("order")
        select element);

Автор: Vit 1.4.2008, 15:42
Цитата(mr.DUDA @  1.4.2008,  01:28 Найти цитируемый пост)
Если делать руками, то так:


Спасибо!

Цитата(mr.DUDA @  1.4.2008,  01:28 Найти цитируемый пост)
З.Ы. кстати твой XML невалидный, исправил:


Ну я ж не реальный XML дал, а так, то что от руки набросал, чтобы только смысл передать...

Цитата(Rififi @  1.4.2008,  03:08 Найти цитируемый пост)
указанная задача решается с помощью .NET 3.5 и Linq to XML, или XSLT, или даже XQuery
первое проще всего, вот небольшой пример для подузла child1, остальное - по аналогии.



.NET 3.5 - не подходит, задачу надо решить в 2.0


 Linq to XML, или XSLT, или даже XQuery - к сожалению не знаком с этими технологиями, но посмотрю.

Автор: Rififi 1.4.2008, 15:49
Цитата
.NET 3.5 - не подходит, задачу надо решить в 2.0

а тебя не бесит, когда задается вопрос, а потом выясняется что вот этого нельзя, потому что у меня не то, а это вообще не так? smile:

Автор: mr.DUDA 1.4.2008, 16:41
Rififi, если явно не указано на какой платформе нужно решение, подразумевается наиболее широко распространённая на данный момент. Сейчас актуальнее всего 2.0, под 3.5 слишком мало софта. Будем считать тему платформы закрытой.

P.S. может быть можно то же самое сделать на XPath/XQuery, но с этими технологиями знаком слабо, поэтому привёл простейший вариант "в лоб"


M
mr.DUDA
P.S.(2) уважаемые all, просьба высказывать меньше эмоций в общих топиках

Автор: Vit 3.4.2008, 17:37
mr.DUDA, спасибо!

Способ работает, пришлось сделать небольшую рехтовку под местные условия, но это мелочи. Большое спасибо!

Автор: mr.DUDA 3.4.2008, 20:08
You are welcome  smile 

Автор: butalex11 27.12.2011, 13:38
Здравствуйте! Очень нужна такая же сортировка, как у топикстартера, только нужно по текстовым аттрибутам, а не по int... Можете подсказать, пожалуйста, как изменить код, который написал mr.DUDA ? Заранее спасибо...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)