2009-03-22 19 views
176

Mam ten plik XMLLINQ do odczytu 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> 

mógłby ktoś podać mi kod C# za pomocą najprostszy sposób LINQ, aby wydrukować ten wynik:
(zwróć uwagę na dodatkową przestrzeń, jeśli jest to węzeł level2)

A 
    A1 
    A2 
B 
    B1 
    B2 
C 

Obecnie mam ten kod

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

Oto dobry przykład tego, co u potrzeba: [C XML # obciążenia przy użyciu XLINQ (LINQ do XML)] (http: //www.codearsenal.net/2012/07/c-sharp-load-xml-using-xlinq.html) –

Odpowiedz

203

Spróbuj tego.

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

To spojrzenie jest rodzajem podejścia "zakodowanego". – Mohanavel

+2

@bendewey Zadaję podobne pytanie, czy mógłbyś to sprawdzić, tutaj: http://stackoverflow.com/questions/13247449/customize-xml-serialize-with-new-tags-and-attributes-and-root – Saeid

+1

It to tak, jakby wziąć lotniskowca tylko po to, by łowić ryby. – 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); 
} 

Ps. Musisz użyć .Root w dowolnej z tych wersji.

+0

Czy to nie drukuje wszystkich poziomów 2 po wszystkich level1? – sblom

+0

@sblom oops, zgadza się, zaktualizował to, co miałem zamiar opublikować (przeprowadziłem test przeciwko niemu, więc jestem pewien, że teraz działa :)) – eglasius

21

Kilka prostych starych foreach pętli zapewnia czystą rozwiązanie:

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

Albo, jeśli chcesz bardziej ogólne podejście - to znaczy do zagnieżdżania się do "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 ogólne podejście, elegancka rekursja – Askolein

17

Tutaj to kilka pełnych przykładów pracy, które bazują na @dobowiązujących przykładach @bendewey. Musiałem dostosować każdy z nich trochę się zmusić go do pracy, ale w przypadku innego noobem LINQ szuka przykłady pracy, tutaj przejść:

//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 
    } 
} 

I dalej:

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

one zarówno skompilować & pracować w VS2010 przy użyciu csc.exe w wersji 4.0.30319.1 i podać dokładnie to samo wyjście. Mam nadzieję, że to pomoże komuś, kto szuka działających przykładów kodu. Przykładem dodany @eglasius' jak dobrze, ponieważ stał się użyteczny do mnie:

edytować

//@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 
    } 
}