2010-02-24 6 views
5

XML Probe (original link):Wie kann ich alle „Eigenschaften“ aus xml über Linq erhalten, um XML-

<records> 
    <record index="1"> 
    <property name="Username">Sven</property> 
    <property name="Domain">infinity2</property> 
    <property name="LastLogon">12/15/2009</property> 
    </record> 
    <record index="2"> 
    <property name="Username">Josephine</property> 
    <property name="Domain">infinity3</property> 
    <property name="LastLogon">01/02/2010</property> 
    </record> 
    <record index="3"> 
    <property name="Username">Frankie</property> 
    <property name="Domain">wk-infinity9</property> 
    <property name="LastLogon">10/02/2009</property> 
    </record> 
</records> 

Ich will eine Instanz einer Klasse pro Datensatz in der XML erhalten.

Ich fand ähnliche Beispiele hier, aber sie hatten nur eine Wurzel, dann ein Element tief. Es funktioniert, bis, bis ich in das andere Element lege ich etwas zu tun, wie

foreach(Record rec in myVar) 
{ 
Console.WriteLine("ID: {0} User:{1} Domain:{2} LastLogon:{3}",rec.Index, rec.Username, rec.Domain, rec.LastLogon); 
} 

Antwort

3

EDIT in der Lage sein wollen. aktualisierten Code mit ToDictionary Ansatz für Klarheit und Effizienz.

Sie können das folgende Beispiel versuchen. Wenn Sie Record aus der Zeile select new Record entfernen, wird dies zu einem anonymen Typ führen und trotzdem funktionieren. Ihre Klasse Record sollte einen parameterlosen Standardkonstruktor haben, um den Objektinitialisierer zu verwenden, wenn Sie andere Konstruktoren bereitgestellt haben (dies funktioniert auch, wenn Sie keine Konstruktoren haben). Andernfalls können Sie die verfügbaren Konstruktoren anstelle des Objektinitialisierers verwenden.

Beachten Sie, dass bei der Verwendung von Single() und Value davon ausgegangen wird, dass das XML gut formatiert ist und keine fehlenden Elemente enthält.

var xml = XElement.Parse(@"<records> 
<record index=""1""> 
    <property name=""Username"">Sven</property> 
    <property name=""Domain"">infinity2</property> 
    <property name=""LastLogon"">12/15/2009</property> 
</record> 
<record index=""2""> 
    <property name=""Username"">Josephine</property> 
    <property name=""Domain"">infinity3</property> 
    <property name=""LastLogon"">01/02/2010</property> 
</record> 
<record index=""3""> 
    <property name=""Username"">Frankie</property> 
    <property name=""Domain"">wk-infinity9</property> 
    <property name=""LastLogon"">10/02/2009</property> 
</record> 
</records>"); 

var query = from record in xml.Elements("record") 
     let properties = record.Elements("property") 
           .ToDictionary(p => p.Attribute("name").Value, p => p.Value) 
     select new Record 
     { 
      Index = record.Attribute("index").Value, 
      Username = properties["Username"], 
      Domain = properties["Domain"], 
      LastLogon = properties["LastLogon"] 
     }; 

foreach(var rec in query) 
{ 
    Console.WriteLine("ID: {0} User:{1} Domain:{2} LastLogon:{3}", rec.Index, rec.Username, rec.Domain, rec.LastLogon); 
} 

EDIT: Ich habe das Codebeispiel oben mit dem ToDictionary Ansatz aktualisiert, die sauberen und schneller. Basierend auf meinen Benchmark-Bemühungen war der schnellste Weg ToDictionary, gefolgt von Func und dann der Where Ansatz.

Original-Abfrage

var query = from record in xml.Elements("record") 
      let properties = record.Elements("property") 
      select new Record 
      { 
       Index = record.Attribute("index").Value, 
       Username = properties.Where(p => p.Attribute("name").Value == "Username").Single().Value, 
       Domain = properties.Where(p => p.Attribute("name").Value == "Domain").Single().Value, 
       LastLogon = properties.Where(p => p.Attribute("name").Value == "LastLogon").Single().Value 
      }; 

Abfrage mit Func

Redundanz der ursprünglichen Abfrage kann mit dem folgenden Code reduzieren:

Func<XElement, string, string> GetAttribute = 
      (e, property) => e.Elements("property") 
          .Where(p => p.Attribute("name").Value == property) 
          .Single().Value; 

var query = from record in xml.Elements("record") 
      select new Record 
      { 
       Index = record.Attribute("index").Value, 
       Username = GetAttribute(record, "Username"), 
       Domain = GetAttribute(record, "Domain"), 
       LastLogon = GetAttribute(record, "LastLogon") 
      }; 
+0

Perfict! Ich habe versucht, das jetzt für 2-3 Tage herauszufinden. Meine Stirn ist wund und rot. Welche Bücher empfehlen Sie für LINQ (und C#). –

+0

@Sunzaru Ich mag LINQ in Aktion (http://www.amazon.com/dp/1933988169/) oder Sie möchten vielleicht ein C# 4.0/.NET 4.0 Buch, um einige der neuen Materialien zu decken. C# 4.0 in einer Nussschale ist gut, aber es deckt viel Material ab. Ich empfehle auch, LINQPad (http://www.linqpad.net/) zu downloaden und die mitgelieferten Kurzshell-Samples durchzugehen (vom Autor des Buches). Sie können die LINQ in Action-Beispiele auch herunterladen. Vielleicht tun Sie das zuerst, bevor Sie ein Buch kaufen :) –

+0

Ich testete es heute gab es eine durchschnittliche Prozesszeit von 120MS. Aber in diesen 120MS suchte ich auch nach einigen anderen Indikatoren, die oben nicht erwähnt wurden. schnell .. slick und zomg .. sooo viel besser als "Edit-> Find". Danke noch einmal! –