2009-03-22 23 views
176

Tengo este archivo XMLLINQ para leer XML

<root> 
    <level1 name="A"> 
     <level2 name="A1" /> 
     <level2 name="A2" /> 
    </level1> 
    <level1 name="B"> 
     <level2 name="B1" /> 
     <level2 name="B2" /> 
    </level1> 
    <level1 name="C" /> 
</root> 

Podría alguien me da un código en C# usando LINQ, la forma más sencilla de imprimir este resultado:
(Tenga en cuenta el espacio adicional si es un nodo de nivel 2)

A 
    A1 
    A2 
B 
    B1 
    B2 
C 

Actualmente tengo este código

XDocument xdoc = XDocument.Load("data.xml")); 
var lv1s = from lv1 in xdoc.Descendants("level1") 
      select lv1.Attribute("name").Value; 

foreach (var lv1 in lv1s) 
{ 
    result.AppendLine(lv1); 

    var lv2s = from lv2 in xdoc...??? 
} 
+14

Aquí es buen ejemplo de lo que la necesidad de u: [C# Cargar XML utilizando XLINQ (LINQ to XML)] (http: //www.codearsenal.net/2012/07/c-sharp-load-xml-using-xlinq.html) –

Respuesta

203

Prueba esto.

void Main() 
{ 
    StringBuilder result = new StringBuilder(); 

    //Load xml 
    XDocument xdoc = XDocument.Load("data.xml"); 

    //Run query 
    var lv1s = from lv1 in xdoc.Descendants("level1") 
       select new { 
        Header = lv1.Attribute("name").Value, 
        Children = lv1.Descendants("level2") 
       }; 

    //Loop through results 
    foreach (var lv1 in lv1s){ 
      result.AppendLine(lv1.Header); 
      foreach(var lv2 in lv1.Children) 
       result.AppendLine("  " + lv2.Attribute("name").Value); 
    } 

    Console.WriteLine(result); 
} 
+23

Este aspecto es una especie de enfoque "codificado". – Mohanavel

+2

@bendewey Hago una pregunta similar, ¿podría verificarla, aquí: http://stackoverflow.com/questions/13247449/customize-xml-serialize-with-new-tags-and-attributes-and-root – Saeid

+1

It es como llevar un portaaviones solo para ir a pescar. – TomeeNS

8
XDocument xdoc = XDocument.Load("data.xml"); 
var lv1s = xdoc.Root.Descendants("level1"); 
var lvs = lv1s.SelectMany(l=> 
    new string[]{ l.Attribute("name").Value } 
    .Union(
     l.Descendants("level2") 
     .Select(l2=>" " + l2.Attribute("name").Value) 
    ) 
    ); 
foreach (var lv in lvs) 
{ 
    result.AppendLine(lv); 
} 

Sal. Debes usar .Root en cualquiera de estas versiones.

+0

¿Esto no imprime todos los niveles 2 después de todos los level1? – sblom

+0

@sblom oops, eso es correcto, lo actualicé con lo que quise publicar (ejecuté una prueba en contra, así que estoy seguro de que funciona ahora :)) – eglasius

21

Un par de llanura viejos foreach bucles proporciona una solución limpia:

foreach (XElement level1Element in XElement.Load("data.xml").Elements("level1")) 
{ 
    result.AppendLine(level1Element.Attribute("name").Value); 

    foreach (XElement level2Element in level1Element.Elements("level2")) 
    { 
     result.AppendLine(" " + level2Element.Attribute("name").Value); 
    } 
} 
48

O, si quieres un enfoque más general - es decir, para anidados hasta "levelN":

void Main() 
{ 
    XElement rootElement = XElement.Load(@"c:\events\test.xml"); 

    Console.WriteLine(GetOutline(0, rootElement)); 
} 

private string GetOutline(int indentLevel, XElement element) 
{ 
    StringBuilder result = new StringBuilder(); 

    if (element.Attribute("name") != null) 
    { 
     result = result.AppendLine(new string(' ', indentLevel * 2) + element.Attribute("name").Value); 
    } 

    foreach (XElement childElement in element.Elements()) 
    { 
     result.Append(GetOutline(indentLevel + 1, childElement)); 
    } 

    return result.ToString(); 
} 
+9

+1 enfoque genérico, recursión elegante – Askolein

17

Aquí hay un par de ejemplos de trabajo completos que se basan en @bendewey & @dommer ejemplos. Que necesitaba para ajustar cada uno de ellos un poco para conseguir que funcione, pero en caso de que otro novato LINQ está en busca de ejemplos de trabajo, aquí van:

//bendewey's example using data.xml from OP 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Xml.Linq; 

class loadXMLToLINQ1 
{ 
    static void Main() 
    { 
     //Load xml 
     XDocument xdoc = XDocument.Load(@"c:\\data.xml"); //you'll have to edit your path 

     //Run query 
     var lv1s = from lv1 in xdoc.Descendants("level1") 
      select new 
      { 
       Header = lv1.Attribute("name").Value, 
       Children = lv1.Descendants("level2") 
      }; 

     StringBuilder result = new StringBuilder(); //had to add this to make the result work 
     //Loop through results 
     foreach (var lv1 in lv1s) 
     { 
      result.AppendLine(" " + lv1.Header); 
      foreach(var lv2 in lv1.Children) 
      result.AppendLine(" " + lv2.Attribute("name").Value); 
     } 
     Console.WriteLine(result.ToString()); //added this so you could see the output on the console 
    } 
} 

Y a continuación:

//Dommer's example, using data.xml from OP 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Xml.Linq; 

class loadXMLToLINQ 
{ 
static void Main() 
    { 
     XElement rootElement = XElement.Load(@"c:\\data.xml"); //you'll have to edit your path 
     Console.WriteLine(GetOutline(0, rootElement)); 
    } 

static private string GetOutline(int indentLevel, XElement element) 
    { 
     StringBuilder result = new StringBuilder(); 
     if (element.Attribute("name") != null) 
     { 
      result = result.AppendLine(new string(' ', indentLevel * 2) + element.Attribute("name").Value); 
     } 
     foreach (XElement childElement in element.Elements()) 
     { 
      result.Append(GetOutline(indentLevel + 1, childElement)); 
     } 
     return result.ToString(); 
    } 
} 

Estos dos compilar & funcionan en VS2010 utilizando csc.exe versión 4.0.30319.1 y dan el mismo resultado exacto. Esperemos que estos ayuden a alguien más que esté buscando ejemplos de código de trabajo. ejemplo añadido @eglasius' así desde que se hizo útil para mí::

EDIT

//@eglasius example, still using data.xml from OP 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Xml.Linq; 

class loadXMLToLINQ2 
{ 
    static void Main() 
    { 
     StringBuilder result = new StringBuilder(); //needed for result below 
     XDocument xdoc = XDocument.Load(@"c:\\deg\\data.xml"); //you'll have to edit your path 
     var lv1s = xdoc.Root.Descendants("level1"); 
     var lvs = lv1s.SelectMany(l=> 
      new string[]{ l.Attribute("name").Value } 
      .Union(
       l.Descendants("level2") 
       .Select(l2=>" " + l2.Attribute("name").Value) 
      ) 
      ); 
     foreach (var lv in lvs) 
     { 
      result.AppendLine(lv); 
     } 
     Console.WriteLine(result);//added this so you could see the result 
    } 
}