2016-09-01 6 views
4

Я борюсь с этой сортировкой и нуждаюсь в небольшой помощи.Сортировка с LINQ

Я буду сортировать дочерние узлы вдоль ранга и сохранить его. , например. для упорядочивания вспомогательных узлов внутри основного элемента я передам идентификатор для конкретного раздела.

Этот пример работает только для первых потомков, и теперь я застрял.

XElement x = XElement.Load(xmlString1); 
x.Descendants("opt").First().ReplaceNodes(x.Descendants("opt").First() 
.Descendants("sel").OrderBy(o => int.Parse(o.Attribute("rank").Value))); 
4x.Save(xmlString2); 

Мне это нужно.

x.Descendants("sub").Where(b => b.Attribute("id").Value == "DFG") 
.ReplaceNodes(x.Descendants("opt").First() 
.Descendants("sel").OrderBy(o => int.Parse(o.Attribute("rank").Value)) 

Оригинал

<main id="AFB" rank="1" name="ROOT"> 
<sub id="DFG" rank="2" name="SUB1"> 
<att > 
    <sel id="JIK" rank="4" name="444" /> 
    <sel id="OKI" rank="2" name="222" /> 
    </att> 
    <opt> 
    <sel id="JIK" rank="2" name="122" /> 
    <sel id="OKI" rank="1" name="111" /> 
    </opt> 
</sub> 
<sub id="EGG" rank="1" name="SUB2" > 
    <opt> 
    <sel id="DJI" rank="1" name="111" /> 
    <sel id="LOW" rank="3" name="333" /> 
    <sel id="QWE" rank="2" name="222" /> 
    </opt> 
</sub> 
<main> 

Target

<main id="AFB" rank="1" name="ROOT"> 
<sub id="EGG" rank="1" name="SUB2" > 
    <opt> 
    <sel id="DJI" rank="1" name="111" />   
    <sel id="QWE" rank="2" name="222" /> 
    <sel id="LOW" rank="3" name="333" /> 
    </opt> 
</sub> 
<sub id="DFG" rank="2" name="SUB1"> 
    <att > 
    <sel id="OKI" rank="2" name="222" /> 
    <sel id="JIK" rank="4" name="444" />   
    </att> 
    <opt> 
    <sel id="OKI" rank="1" name="111" /> 
    <sel id="JIK" rank="2" name="122" />   
    </opt> 
</sub> 
<main> 
+1

Я редактировал свой пост, чтобы правильно форматировать код и сделать его доступным для чтения. Но '4x.Save (xmlString2);' был там раньше, и я не изменяю * код * при редактировании. Это опечатка? –

+1

Вы попробовали рекурсию? – slawekwin

ответ

1

Я думаю, что у вас есть там опечаток. Тем не менее, обратите внимание на это решение:

var text = @" 
<main id='AFB' rank='1' name='ROOT'> 
    <sub id='DFG' rank='2' name='SUB1'> 
     <opt> 
      <sel id='JIK' rank='4' name='444' /> 
      <sel id='OKI' rank='2' name='222' /> 
     </opt> 
     <opt> 
      <sel id='JIK' rank='2' name='122' /> 
      <sel id='OKI' rank='1' name='111' /> 
     </opt> 
    </sub> 
    <sub id='EGG' rank='1' name='SUB2' > 
     <opt> 
      <sel id='DJI' rank='1' name='111' /> 
      <sel id='LOW' rank='3' name='333' /> 
      <sel id='QWE' rank='2' name='222' /> 
     </opt> 
    </sub> 
</main>"; 

var x = XDocument.Parse(text); 
x.Root.ReplaceNodes(x.Descendants("sub").OrderBy(a => int.Parse(a.Attribute("rank").Value))); 
foreach (var opt in x.Descendants("opt")) 
    opt.ReplaceNodes(opt.Descendants("sel").OrderBy(a => int.Parse(a.Attribute("rank").Value))); 

На данный момент x содержит следующие XML:

<main id="AFB" rank="1" name="ROOT"> 
    <sub id="EGG" rank="1" name="SUB2"> 
    <opt> 
     <sel id="DJI" rank="1" name="111" /> 
     <sel id="QWE" rank="2" name="222" /> 
     <sel id="LOW" rank="3" name="333" /> 
    </opt> 
    </sub> 
    <sub id="DFG" rank="2" name="SUB1"> 
    <opt> 
     <sel id="OKI" rank="2" name="222" /> 
     <sel id="JIK" rank="4" name="444" /> 
    </opt> 
    <opt> 
     <sel id="OKI" rank="1" name="111" /> 
     <sel id="JIK" rank="2" name="122" /> 
    </opt> 
    </sub> 
</main> 

Если att есть вместо «opt` и должны быть включены следующие будут работать:

var x = XDocument.Parse(text); 
x.Root.ReplaceNodes(x.Descendants("sub").OrderBy(a => int.Parse(a.Attribute("rank").Value))); 
foreach (var opt in x.Descendants("sub").Elements()) 
    opt.ReplaceNodes(opt.Descendants("sel").OrderBy(a => int.Parse(a.Attribute("rank").Value))); 

Если вам нужно отсортировать один элемент по названию, используйте следующие (если атрибут ранга не существует или пуст, наденьте его обратно):

//sub with id=EGG 
var sub2 = x.Descendants("sub").FirstOrDefault(a => a.Attribute("id").Value == "EGG"); 
if (sub2 != null) 
{ 
    foreach (var node in sub2.Elements()) 
     node.ReplaceNodes(node.Elements().OrderBy(a => 
     { 
      int rank; 
      if (a.Attribute("rank") == null || !int.TryParse(a.Attribute("rank").Value, out rank)) 
       rank = int.MaxValue; 
      return rank; 
     })); 
} 
+0

Большое спасибо за быстрый ответ. Я попробую. – andy

+0

Добавлен еще один пример. –

+0

?. является null условным оператором (https://msdn.microsoft.com/en-us/library/dn986595.aspx), чтобы предотвратить «NullReferenceException». Какая ошибка? –

0

Даже если это не прямой ответ на вашу проблему, я хочу предложить вам способ избежать прямого обращения с Xml через XDocument и связанные с ним классы.

Когда вы работаете с xml (если файлы .xsd еще не предоставлены), я стараюсь избегать ручного разбора, создав соответствующий ему .xsd и из которого я генерирую классы, необходимые для работы с xml.

открытая визуальная студия подсказка:

-> xsd "yourxml.xml" (a .xsd file will be generated) 
    -> xsd /c "yourxml.xsd" (a .cs file will be generated) 

(Обратите внимание, что вы, возможно, придется настроить сгенерированный XSD вручную, чтобы лучше соответствовать вашим потребностям и применять дополнительные контрсилами)

Класс необходим для хранения информации о xml генерируется.

Теперь вы можете прочитать весь xml в строго типизированном объекте, используя класс, сгенерированный в файле .cs.Вам просто нужно импортировать файл .cs в проекте и десериализации исходный XML:

string fileContent = File.ReadAllText(fileLocation); 
var xmlObj = StringXmlSerializer.XmlDeserialize<YourXsdGeneratedType>(fileContent); 

Вы можете редактировать XML-файл в память и сериализовать обратно в XML, как это:

string xmlContext = StringXmlSerializer.XmlSerialize(xmlObj); 
File.WriteAllText(filePath, xmlObj); 

StringXmlSerializer является вспомогательным i class i написал, что мне нужно сериализовать в памяти строку (но вы можете сериализовать непосредственно в файле). Я разместить код, чтобы вы начали на что:

/// <summary> 
/// Serialize object in xml format on a string 
/// </summary> 
public static class StringXmlSerializer 
{ 
    public static string XmlSerialize(object objectInstance) 
    { 
     XmlWriterSettings ws = new XmlWriterSettings(); 
     ws.NewLineHandling = NewLineHandling.Entitize; 

     var serializer = new XmlSerializer(objectInstance.GetType()); 
     var sb = new StringBuilder(); 

     using(XmlWriter xmlWriter = XmlWriter.Create(sb, ws)) 
      serializer.Serialize(xmlWriter, objectInstance); 

     return sb.ToString(); 
    } 

    public static T XmlDeserialize<T>(string objectData) 
    { 
     return (T)XmlDeserialize(objectData, typeof(T)); 
    } 

    public static object XmlDeserialize(string objectData, Type type) 
    { 
     var serializer = new XmlSerializer(type); 

     using(TextReader reader = new StringReader(objectData)) 
      return serializer.Deserialize(reader); 
    } 
} 

Надеется, что это помогает кто-то

Смежные вопросы