2011-03-27 45 views
2

我想用LINQ排序XML文件。 XML在下面,只是一個例子。通常它會更大更復雜。 XML應按標題排序,按升序排序。一次不是整個XML,而是每個parentNode。葉子總是在底部。文件夾或非葉子在頂部。以下XML已經結構良好,但標題順序錯誤。排序算法還應該替換錯誤定位的非葉節點。 我已經有一些代碼可以完成這項工作,但我想知道是否有更優雅或更短的方式。此刻,我必須調用一個函數遞歸來創建結果。也許這可以用另一種方式完成。 謝謝。使用LINQ排序XML

劉若英

這裏是我的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);       
} 
+0

LINQ不會在遞歸Excel,您方法似乎是確定(但爲什麼一個行動,而不是正確的方法是什麼?) – 2011-03-27 20:12:47

回答

6

的XML應該由標題進行排序, 遞增。不是一次寫入整個XML,而是每個父節點都有自己的 。葉子 總是在底部。文件夾或 非葉子在頂部。

該解決方案似乎滿足您的要求:

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

是你得到它!這正是我所期待的。謝謝! 我不得不改變orderBy-line,因爲我在示例中簡化了XML太多。真正的XML沒有leaf-attribute,bute一個type-attribute,它可以有多個值,不僅是「yes」和「no」。而重要的類型是「文件夾」,它必須按照排序順序(如leaf =「no」)突出顯示。所以這是我的orderBy-line: .OrderBy(x =>(string)x.Attribute(「type」)。Value ==「folder」?1:2) 你對它有什麼看法? – Rene 2011-03-28 08:36:26

+0

更正的行:.OrderBy(x =>(字符串)x.Attribute(「type」)==「文件夾」?1:2) – Rene 2011-03-28 08:52:20

+0

@Rene:是的,以後會工作 – BrokenGlass 2011-03-28 12:51:34