2010-03-11 103 views
3

我有以下可存儲記錄和錯誤的XML文檔(可根據需要進行重新設計)。訂購XElements

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

了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."); 
     } 
    }