2010-02-24 18 views
5

XML de ejemplo (original link):¿Cómo consigo todas las "propiedades" de XML a través de 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> 

Estoy queriendo obtener una instancia de una clase por registro en el xml.

encontré ejemplos similares aquí pero solo tenían una raíz, luego un elemento de profundidad. Funciona, justo hasta que puse otro elemento que quiero ser capaz de hacer algo como

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

Respuesta

3

EDIT:. código actualizado con ToDictionary enfoque para mayor claridad y eficacia.

Puede probar la siguiente muestra. Si elimina Record de la línea select new Record, obtendrá un tipo anónimo y seguirá funcionando. Su clase Record debe tener un constructor sin parámetros predeterminado para usar el inicializador de objetos si ha proporcionado otros constructores (también funcionará si no tiene constructores). De lo contrario, puede usar los constructores disponibles en lugar del inicializador de objetos.

Tenga en cuenta que el uso de Single() y Value supone que el XML está bien formado sin elementos faltantes.

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: He actualizado el ejemplo de código anterior con el enfoque ToDictionary que es más limpio y más rápido. En base a mis esfuerzos de evaluación comparativa, el más rápido fue ToDictionary, seguido por Func, y luego el enfoque Where.

búsqueda original

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

de consultas con Func

redundancia de la consulta original puede ser reducido utilizando el siguiente código:

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! Estuve tratando de resolver esto por 2 o 3 días. Mi cabeza está dolorida y roja. ¿Qué libros recomiendas para verificar LINQ (y C#)? –

+0

@Sunzaru Me gusta LINQ in Action (http://www.amazon.com/dp/1933988169/) o es posible que desee obtener un libro de C# 4.0/.NET 4.0 para cubrir parte del nuevo material. C# 4.0 en una cáscara de nuez es bueno pero cubre mucho material. También recomiendo descargar LINQPad (http://www.linqpad.net/) y revisar las muestras de Nutshell que vienen con él (realizadas por el autor del libro). También puede descargar el LINQ en muestras de Acción a través de él. Tal vez lo haga primero antes de comprar un libro :) –

+0

lo probé hoy hubo un tiempo de proceso promedio de 120MS. pero en esos 120MS también estaba buscando algunos otros indicadores no mencionados anteriormente. rápido ... resbaladizo y zomg ... Mucho mejor que "Editar-> Buscar". ¡gracias de nuevo! –