Заказ XElements - PullRequest
       24

Заказ XElements

3 голосов
/ 11 марта 2010

У меня есть следующий XML-документ (который может быть изменен при необходимости), в котором хранятся записи и ошибки.

<MYROOT>  
  <RECORDS>
    <RECORD>
      <DATETIME>11/03/2010 14:12:41</DATETIME>
      <DOCUMENTID>1</DOCUMENTID>
    </RECORD>
    <RECORD>
      <DATETIME>11/03/2010 14:12:44</DATETIME>
      <DOCUMENTID>2</DOCUMENTID>
    </RECORD>
    <RECORD>
      <DATETIME>11/03/2010 14:12:45</DATETIME>
      <DOCUMENTID>3</DOCUMENTID>
    </RECORD>
  </RECORDS>
  <ERRORS>
    <ERROR TYPE="ERR">
      <DATETIME>11/03/2010 14:12:41</DATETIME>
      <DETAIL>There has been a error on page 1</DETAIL>
    </ERROR>
    <ERROR TYPE="ERR">
      <DATETIME>11/03/2010 14:13:03</DATETIME>
      <DETAIL>There has been a error on page 101</DETAIL>
    </ERROR>
    <ERROR TYPE="SEQ">
      <DATETIME>11/03/2010 14:13:03</DATETIME>
      <DETAIL>Sequence Error, expected Sequence No. 101 Read 1</DETAIL>
    </ERROR>
  </ERRORS>
</MYROOT>

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

Как мне отсортировать их по дате, получить коллекцию XElements, а затем просто выполнить цикл foreach над ними?

Ответы [ 3 ]

3 голосов
/ 11 марта 2010
XDocument xml = System.Xml.Linq.XDocument.Parse(YOUR_XML);
IEnumerable<XElement> records = xml.Root.Element("RECORDS").Elements();
IEnumerable<XElement> errors = xml.Root.Element("ERRORS").Elements();

IEnumerable<XElement> elements = from el in records.Concat(errors)
                                 orderby DateTime.Parse(el.Element("DATETIME").Value)
                                  select el;

foreach (XElement el in elements)
{
    // do something.
}
1 голос
/ 11 марта 2010
var elements = doc.Descendants("RECORD").Concat(doc.Descendants("ERROR")).
    OrderBy(x => DateTime.Parse(x.Element("DATETIME").Value));
foreach (XElement element in elements)
{
    // do something interesting with element
}
0 голосов
/ 12 августа 2015

IEnumerable не очень гибок, лучшим вариантом может быть удаление элементов из перечисляемого, их сортировка и повторная вставка, поддерживая правильный порядок (относительно предыдущих соседей). Немного сложнее, если подэлемент является ключом сортировки

Это удалит именованные элементы из IEnumerable, отсортирует их по подэлементу (может или не может быть тем, что вам нужно) и повторно вставит их в нужное место.

 private void SortIdNodes(XElement parent, String elementName, String sortElementname)
     {
         XNode prevElem = null;
         XNode nextElem = null;
         // Initial node count, to verify sets are equal
         int initialElementsCount = parent.Descendants().Count();
         List<XElement> unOrdered = parent.Descendants(elementName).ToList<XElement>();
         if (unOrdered.Count() < 2){
             return; // No sorting needed
         }
         // Make note of the neighbors
         prevElem = unOrdered[0].PreviousNode;
         nextElem = unOrdered.Last().NextNode;
         // Remove set from parent
         unOrdered.ForEach(el =>
         {
             el.Remove();
         });
         // Order the set, language (IEnumerable) semantics prevents us from changing order in place
         List <XElement> ordered =  unOrdered.OrderBy(x => x.Descendants(sortElementname).FirstOrDefault().Value).ToList<XElement>();
         // Add to parent in correct order
         if (prevElem != null)  // If there's a first neighbor
         {
             ordered.ForEach(el =>
             {
                 prevElem.AddAfterSelf(el);
                 prevElem = el;
             });
         }
         else if (nextElem != null)  // If there's only an end neighbor
         {
             ordered.Reverse();
             ordered.ForEach(el =>
             {
                 nextElem.AddBeforeSelf(el);
                 nextElem = el;
             });
         }
         else // we're the only children of the parent, just add
         {
             ordered.ForEach(el =>
             {
                 parent.Add(el); // add in order
             });
         }
         int finalElementCount = parent.Descendants().Count();
         if (initialElementsCount != finalElementCount)
         {
             throw new Exception("Error with element sorting, output collection not the same size as the input set.");
         }
     }
...