2011-10-25 12 views
6

Tengo un archivo xml que devuelve un conjunto de elementos que son únicos por un valor de atributo. Esto presenta un problema, ya que no puedo seleccionar un nodo por su nombre:Linq a XML seleccionando un nodo bases en un valor de atributo

<doc> 
    <float name="score">1.2873721</float> 
    <arr name="2_category"> 
     <long>3021</long> 
    </arr> 
    <arr name="ATR_FamilyName"> 
     <str>Some Cookbook </str> 
    </arr> 
    <arr name="ATR_IsFamily"> 
     <str>0</str> 
    </arr> 
    <arr name="ATR_SellPrice"> 
     <str>49.95</str> 
    </arr> 
    <arr name="ATR_VendorId"> 
     <str>ABC</str> 
    </arr> 
    <arr name="ATR_VendorName"> 
     <str>WROX</str> 
    </arr>  
</doc> 

estoy usando LINQ para poblar una clase de "producto". Puedo seleccionar los elementos por posición, sin embargo, esto se convierte en un problema si el nodo no existe. ¿Hay alguna manera de seleccionar un nodo en función del valor de su atributo? En el siguiente ejemplo, ¿puedo obtener el nodo arr si el atributo @name = "ATR_FamilyName"? En XPath sería:

doc/arr[@name = 'ATR_FamilyName']/str 

aquí es mi consulta LINQ to XML:

var query = from rt in results 
    where (String)rt.Descendants().ElementAt(5).Element("str").Value == "0" 
    select new Product.Product 
      { 
       FamilyName = (String)rt.Descendants().ElementAt(3).Value 
       // doc/arr[@name = 'ATR_FamilyName']/str - select Family Name is arr/@name 'ATR_FamilyName'        
       MorePropertiestoset....        
       }; 

Respuesta

17

Como la respuesta de AS-CII, pero sin usar una expresión de consulta (excepto la externa), y con el molde para XAttribute, y seleccionando el valor del elemento str dentro de un tipo anónimo:

select new Product.Product 
{ 
    FamilyName = rt.Descendants("arr") 
        .Where(x => (string) x.Attribute("name") == "ATR_FamilyName") 
        .Select(x => (string) x.Element("str")) 
        .FirstOrDefault(), 
    MorePropertiesToSet....        
}; 

Tenga en cuenta que el uso de un yeso por el resultado de la llamada a Attribute("name") significa que si hay elementos que no hacer tener el atributo, el elenco se traducirá en una referencia nula (que ISN 't igual al literal de la cadena). Si usa la propiedad Value, obtendrá una excepción. En ocasiones, una excepción puede ser mejor, si eso indica que los datos están fundamentalmente rotos y desea conocerlos en lugar de simplemente no hacer coincidir el valor.

(Lo mismo es cierto para el elenco de la XElement a string.)

+0

Gracias Jon - Usted clavado. Me apropio de la respuesta rápida de todos – PhillyNJ

+0

Thx para la explicación sobre el casting, Jon. Me encontré con situaciones en las que no todos los nodos tenían el atributo y arrojaba una excepción porque usaba .Value en lugar del molde; este fidex es –

5

Con LINQ puede seleccionar fácilmente sólo los nodos que tienen un atributo especificado, así:

var query = from node in results.Descendants("arr") // I believe you could use results.Elements("arr") here 
      where node.Attribute("name").Value == "ATR_FamilyName" 
      select new Product 
      { 
       FamilyName = node.Element("str").Value 
      }; 
2

Uso XElement así:

from rt in results.descendants("<node name>") 
where rt.attribute(attribute name).value == "specified value" 
select rt 

Lo siento por escribir de teléfono celular

Cuestiones relacionadas