2012-06-15 25 views
7

Este es un poco complicado. Decir que tengo este XmlDocumentCómo eliminar todos los XElements vacíos

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

quiero volver este

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

Como cada uno de los hijos de <SubObject> están todos los elementos vacíos que quiero para deshacerse de él. Lo que lo hace desafiante es que no puedes eliminar los nodos cuando estás iterando sobre ellos. Cualquier ayuda sería muy apreciada.

ACTUALIZACIÓN Esto es lo que terminé con.

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); 
} 

Si alguien está interesado en el caso de uso para esto es para un proyecto de ObjectFilter que arme.

+0

Use System.Xml para leer el archivo de configuración –

+4

@sarooptrivedi: Lea la pregunta. – SLaks

+0

@SLaks: Realizo las mismas cosas en mi proyecto. Puede leer el XMLDOcument y luego actualizar el archivo y guardar el xml por fin –

Respuesta

9

que va a ser bastante lento, pero se puede hacer esto:

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()); 
} 

para hacerlo más rápido, que podría subir las nodos padre después de la primera iteración y ver si están vacíos.

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

¡Gracias por la ayuda! – Micah

+0

Tuve el mismo problema y esta solución eliminó solo algunos de los elementos, dejando valores de cadena vacíos. Esta modificación ayudó: 'var empty = xml.Descendants(). Where (x => (x.IsEmpty || string.IsNullOrEmpty (x.Value)) &&! X.HasAttributes) .ToList();' – user5226582

-1

Aquí creo un archivo XML en el que pongo el código all xml. También puede usar el XmlLoad("") para cargar el xml. Esto funcionará con el código de carga de archivos. puedes probar con XmlLoad también.

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(); 
     } 
    } 
} 
Cuestiones relacionadas