2010-08-12 8 views
12

Ich habe ein XDocument, in dem ich alle Elemente alphabetisch sortieren möchte. Hier ist eine vereinfachte Version der Struktur:Sortieren aller Elemente in einem XDocument

<Config> 
<Server> 
    <Id>svr1</Id> 
    <Routing> 
     <RoutingNodeName>route1</RoutingNodeName> 
     <Subscription> 
      <Id>1</Id> 
     </Subscription> 
     <RoutingParameters id="Routing1"> 
      <Timeout>7200</Timeout> 
     </RoutingParameters> 
    </Routing> 
    <Storage> 
      <Physical>HD1</Physical> 
    </Storage> 
</Server> 
<Applications> 
    <Services> 
     <Local></Local> 
    </Services> 
</Applications> 
</Config> 

ich will, um die Elemente in diesen Dokumenten auf allen Ebene sortieren, so weit ich in der Lage bin, es zu sortieren, wie so:

private static XDocument Sort(XDocument file) 
{ 
    return new XDocument(
     new XElement(file.Root.Name, 
      from el in file.Root.Elements() 
      orderby el.Name.ToString() 
      select el)); 
} 

Welche produziert:

<Config> 
<Applications> 
    <Services> 
    <Local></Local> 
    </Services> 
</Applications> 
<Server> 
    <Id>svr1</Id> 
    <Routing> 
    <RoutingNodeName>route1</RoutingNodeName> 
    <Subscription> 
     <Id>1</Id> 
    </Subscription> 
    <RoutingParameters id="Routing1"> 
     <Timeout>7200</Timeout> 
    </RoutingParameters> 
    </Routing> 
    <Storage> 
    <Physical>HD1</Physical> 
    </Storage> 
</Server> 
</Config> 

ich alle Kinder Elemente in der gleichen Art und Weise in der Lage sein möchten, sortieren (durch eine rekursive Funktion im Idealfall). Irgendwelche Ideen, wie ich das mit LINQ umsetzen kann?

Danke für irgendwelche Ideen.

Antwort

18

Sie haben bereits eine Methode zum Sortieren der Elemente. rekursiv anwenden es einfach:

private static XElement Sort(XElement element) 
{ 
    return new XElement(element.Name, 
      from child in element.Elements() 
      orderby child.Name.ToString() 
      select Sort(child)); 
} 

private static XDocument Sort(XDocument file) 
{ 
    return new XDocument(Sort(file.Root)); 
} 

Beachten Sie, dass diese Streifen alle Nicht-Elementknoten (Attribute, Texte, Kommentare, etc.) aus dem Dokument.


Wenn Sie die nicht-Elementknoten behalten möchten, müssen Sie sie über kopieren:

private static XElement Sort(XElement element) 
{ 
    return new XElement(element.Name, 
      element.Attributes(), 
      from child in element.Nodes() 
      where child.NodeType != XmlNodeType.Element 
      select child, 
      from child in element.Elements() 
      orderby child.Name.ToString() 
      select Sort(child)); 
} 

private static XDocument Sort(XDocument file) 
{ 
    return new XDocument(
      file.Declaration, 
      from child in file.Nodes() 
      where child.NodeType != XmlNodeType.Element 
      select child, 
      Sort(file.Root)); 
} 
+0

Dank Ich konnte das verwenden, um mein beabsichtigtes Ergebnis mit den Attributen und dem Text zu erhalten. Prost. –

+0

Dies ist eine großartige Möglichkeit zu zeigen, wie die Knoten zu sortieren, aber loszuwerden alle Werte und Attribute ist keine Antwort, die die OPs Frage [email protected] es wäre toll gewesen, wenn du diese Antwort editiert hättest, um allen anderen zu zeigen, wie du die richtige Antwort gefunden hast, die du suchst. –

+0

@ArvoBowen: Ich habe meine Antwort aktualisiert. – dtb

4
private static XElement Sort(XElement element) 
{ 
    XElement newElement = new XElement(element.Name, 
     from child in element.Elements() 
     orderby child.Name.ToString() 
     select Sort(child)); 
    if (element.HasAttributes) 
    { 
     foreach (XAttribute attrib in element.Attributes()) 
     { 
      newElement.SetAttributeValue(attrib.Name, attrib.Value); 
     } 
    } 
    return newElement; 
} 

private static XDocument Sort(XDocument file) 
{ 
    return new XDocument(Sort(file.Root)); 
} 

Hier ist ein aktualisiertes Beispiel, das alle Attribute enthalten, wenn die Art der Durchführung.

Dieser Beitrag hat mir sehr geholfen, weil ich keine XML-Sortierung mit XSLT durchführen wollte, da ich XML nicht neu formatieren wollte. Ich suchte überall nach einer einfachen Lösung, um eine XML-Sortierung mit C# und ASP.NET durchzuführen, und ich war erfreut, als ich diesen Thread fand. Danke an alle, das hat genau das gemacht, was ich brauchte.

~ Matt

+0

Dies wird nicht erreichen, was das OP will. Dies löscht alle Werte! –

-1

Ich denke, diese Erweiterung Methode funktioniert am besten.

public static class XmlLinq 
{ 
    public static void Sort(this XElement source, bool sortAttributes = true) 
    { 
    if (source == null) 
     throw new ArgumentNullException("source"); 

    if (sortAttributes) 
     source.SortAttributes(); 

    List<XElement> sortedChildren = source.Elements().OrderBy(e => e.Name.ToString()).ToList(); 
    source.RemoveNodes(); 

    sortedChildren.ForEach(c => source.Add(c)); 
    sortedChildren.ForEach(c => c.Sort()); 
    } 

    public static void SortAttributes(this XElement source) 
    { 
    if (source == null) 
     throw new ArgumentNullException("source"); 

    List<XAttribute> sortedAttributes = source.Attributes().OrderBy(a => a.ToString()).ToList(); 
    sortedAttributes.ForEach(a => a.Remove()); 
    sortedAttributes.ForEach(a => source.Add(a)); 
    } 
} 
+0

Dies war eine gute Basis für mich, aber es behält nicht alle Textwerte oder die Attribute. Also musste ich meine eigene Antwort hinzufügen, die mit ein paar Modifikationen gemacht wurde. ;) –

10

Durch dieses Verfahren ist eine REAL DOCUMENT EXTENSION und erhält die Attribute und Textwerte

ich mit dieser Basis aus einem paar verschiedenen Beiträgen und Code von hier kam und dort ... Danke an alle wer hat beigetragen!

im gleichen Namensraum (nicht die gleiche Klasse) fügen Sie den folgenden ...

public static void Sort(this XElement source, bool bSortAttributes = true) 
{ 
    //Make sure there is a valid source 
    if (source == null) throw new ArgumentNullException("source"); 

    //Sort attributes if needed 
    if (bSortAttributes) 
    { 
     List<XAttribute> sortedAttributes = source.Attributes().OrderBy(a => a.ToString()).ToList(); 
     sortedAttributes.ForEach(a => a.Remove()); 
     sortedAttributes.ForEach(a => source.Add(a)); 
    } 

    //Sort the children IF any exist 
    List<XElement> sortedChildren = source.Elements().OrderBy(e => e.Name.ToString()).ToList(); 
    if (source.HasElements) 
    { 
     source.RemoveNodes(); 
     sortedChildren.ForEach(c => c.Sort(bSortAttributes)); 
     sortedChildren.ForEach(c => source.Add(c)); 
    } 
} 

Dokument Erweiterung nutzen zu können, ...

//Load the xDoc 
XDocument xDoc = XDocument.Load("c:\test.xml"); 

//Sort the root element 
xDoc.Root.Sort(); 
+0

Das ist die beste Antwort hier. Habe gerade gearbeitet. Vielen Dank! –

+0

Ändern einer Zeile zu: Liste sortedChildren = source.Elements(). OrderBy (elem => elem.Attributes ("Name"). Any()? Elem.Attributes ("Name"). First(). Wert .ToString(): string.Empty) .ToList(); Und es funktioniert gut, EDMX-Dateien zu sortieren. Danke Arvo –

Verwandte Themen