2010-02-24 1 views
5

XML di esempio (original link):Come posso ottenere tutte le "proprietà" da XML tramite LINQ to 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> 

Sono voler ottenere un'istanza di una classe per ogni record nel xml.

Ho trovato esempi simili qui ma avevano solo una radice, quindi un elemento in profondità. Funziona, fino a quando ho messo altro elemento che voglio essere in grado di fare qualcosa di simile

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

risposta

3

EDIT:. codice aggiornato con ToDictionary approccio per chiarezza ed efficienza.

Puoi provare il seguente esempio. Se si rimuove Record dalla riga select new Record, verrà restituito un tipo anonimo e funzionerà ancora. La tua classe Record dovrebbe avere un costruttore parametrico predefinito per utilizzare l'inizializzatore dell'oggetto se hai fornito altri costruttori (funzionerà anche se non hai costruttori). Altrimenti puoi usare i costruttori disponibili invece dell'inizializzatore dell'oggetto.

Si noti che l'uso di Single() e Value presuppone che l'XML sia ben formato senza elementi mancanti.

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: Ho aggiornato il codice di esempio sopra con l'approccio ToDictionary che è più pulito e veloce. In base ai miei sforzi di benchmarking, il più veloce è stato ToDictionary, seguito da Func e quindi l'approccio Where.

query originale

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

query con Funz

ridondanza della query originale può essere ridotto utilizzando il seguente codice:

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! Ho cercato di capire questo per 2-3 giorni ora. La mia fronte è dolorante e rossa. Quali libri si consiglia di controllare LINQ (e C#). –

+0

@Sunzaru Mi piace LINQ in Action (http://www.amazon.com/dp/1933988169/) o potresti volere un libro C# 4.0/.NET 4.0 per coprire parte del nuovo materiale. C# 4.0 in a Nutshell è buono ma copre molto materiale. Consiglio inoltre di scaricare LINQPad (http://www.linqpad.net/) e di esaminare gli esempi di Nutshell forniti con esso (creati dall'autore del libro). Puoi anche scaricare i campioni LINQ in Action attraverso di essa. Forse lo fai prima di acquistare un libro :) –

+0

l'ho provato oggi c'era un tempo medio di processo di 120MS. ma in quei 120MS cercavo anche alcuni altri indicatori non menzionati sopra. veloce .. slick e zomg .. mooolto molto meglio di "Modifica-> Trova". grazie ancora! –