2012-06-15 14 views
7

Questo è un po 'complicato. Dire che ho questo XmlDocumentCome rimuovere tutti gli XElements vuoti

<Object> 
    <Property1>1</Property1> 
    <Property2>2</Property2> 
    <SubObject> 
     <DeeplyNestedObject /> 
    </SubObject> 
</Object> 

voglio tornare questo

<Object> 
    <Property1>1</Property1> 
    <Property2>2</Property2> 
</Object> 

Poiché ciascuno dei figli di <SubObject> sono tutti gli elementi vuoti che voglio sbarazzarsi di esso. Ciò che lo rende difficile è che non puoi rimuovere i nodi mentre stai iterando su di essi. Qualsiasi aiuto sarebbe molto apprezzato.

AGGIORNAMENTO Ecco di cosa sono finito.

public XDocument Process() 
{ 
    //Load my XDocument 
    var xmlDoc = GetObjectXml(_source); 

    //Keep track of empty elements 
    var childrenToDelete = new List<XElement>(); 

    //Recursively iterate through each child node 
    foreach (var node in xmlDoc.Root.Elements()) 
     Process(node, childrenToDelete); 

    //An items marked for deletion can safely be removed here 
    //Since we're not iterating over the source elements collection 
    foreach (var deletion in childrenToDelete) 
     deletion.Remove(); 

    return xmlDoc; 
} 

private void Process(XElement node, List<XElement> elementsToDelete) 
{ 
    //Walk the child elements 
    if (node.HasElements) 
    { 
     //This is the collection of child elements to be deleted 
     //for this particular node 
     var childrenToDelete = new List<XElement>(); 

     //Recursively iterate each child 
     foreach (var child in node.Elements()) 
      Process(child, childrenToDelete); 

     //Delete all children that were marked as empty 
     foreach (var deletion in childrenToDelete) 
      deletion.Remove(); 

     //Since we just removed all this nodes empty children 
     //delete it if there's nothing left 
     if (node.IsEmpty) 
      elementsToDelete.Add(node); 
    } 

    //The current leaf node is empty so mark it for deletion 
    else if (node.IsEmpty) 
     elementsToDelete.Add(node); 
} 

Se qualcuno è interessato al caso d'uso per questo è per un progetto ObjectFilter ho messo insieme.

+0

Utilizzare la System.Xml per la lettura di file di configurazione –

+4

@sarooptrivedi: Leggi la domanda. – SLaks

+0

@SLaks: eseguo le stesse cose nel mio progetto. È possibile leggere XMLDOcument e quindi aggiornare il file e salvare l'xml alla fine –

risposta

9

sarà piuttosto lento, ma si potrebbe fare questo:

XElement xml; 
while (true) { 
    var empties = xml.Descendants().Where(x => x.IsEmpty && !x.HasAttributes).ToList(); 
    if (empties.Count == 0) 
     break; 

    empties.ForEach(e => e.Remove()); 
} 

per renderla più veloce, si poteva camminare i nodi padre dopo la prima iterazione e vedere se sono vuote.

XElement xml; 
var empties = xml.Descendants().Where(x => x.IsEmpty && !x.HasAttributes).ToList(); 
while (empties.Count > 0) { 
    var parents = empties.Select(e => e.Parent) 
         .Where(e => e != null) 
         .Distinct() //In case we have two empty siblings, don't try to remove the parent twice 
         .ToList(); 

    empties.ForEach(e => e.Remove()); 

    //Filter the parent nodes to the ones that just became empty. 
    parents.RemoveAll(e => e.IsEmpty && !e.HasAttributes); 
    empties = parents; 
} 
+0

Grazie per l'aiuto! – Micah

+0

Ho avuto lo stesso problema e questa soluzione ha rimosso solo alcuni elementi, lasciando valori di stringa vuoti. Questa modifica ha aiutato: 'var empties = xml.Descendants(). Dove (x => (x.IsEmpty || string.IsNullOrEmpty (x.Value)) &&! X.HasAttributes) .ToList();' – user5226582

-1

Qui creo un file XML in cui inserisco il codice tutto xml. È anche possibile utilizzare XmlLoad("") per caricare il xml. Questo funzionerà con il caricamento del file. puoi provare anche con XmlLoad.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Xml; 

namespace Test 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      XmlDocument doc = new XmlDocument(); 
      doc.Load("Test.xml"); 
      XmlElement root = doc.DocumentElement; 
      foreach (var item in root) 
      { 
       XmlElement elem = (XmlElement)item; 
       if (elem.InnerText.Equals("")) 
       { 
        foreach (var child in elem.ChildNodes) 
        { 
         XmlElement childelem = (XmlElement)child; 
         childelem.RemoveAll(); 
        } 

        elem.ParentNode.RemoveChild(elem); 
       } 
      } 
      doc.Save("Test.xml"); 
      Console.ReadLine(); 
     } 
    } 
} 
Problemi correlati