2012-02-07 10 views
13

Ho un documento XML che contiene una serie di nodi oggetto che assomigliano a questo:Il modo migliore per interrogare XDocument con LINQ?

<data> 
    <item> 
     <label>XYZ</label> 
     <description>lorem ipsum</description> 
     <parameter type="id">123</parameter> 
     <parameter type="name">Adam Savage</parameter> 
     <parameter type="zip">90210</parameter> 
    </item> 
</data> 

e voglio LINQ in un tipo anonimo come questo:

var mydata = 
    (from root in document.Root.Elements("item") 
    select new { 
     label = (string)root.Element("label"), 
     description = (string)root.Element("description"), 
     id = ..., 
     name = ..., 
     zip = ... 
    }); 

Qual è il modo migliore tirare ogni tipo di parametro in base al valore del suo attributo 'tipo'? Dato che ci sono molti elementi di parametro, si finisce con root.Elements("parameter") che è una raccolta. Il modo migliore in cui posso pensare di farlo è simile al seguente metodo, ma mi sembra che ci debba essere un modo migliore?

(from c in root.Descendants("parameter") where (string)c.Attribute("type") == "id" 
select c.Value).SingleOrDefault() 

risposta

25

vorrei utilizzare i metodi di query incorporate in LINQ to XML, invece di XPath. La tua query mi sembra a posto, tranne che:

  • Se ci sono più elementi, dovresti invece trovare i discendenti di quello; o semplicemente usare Element se siete alla ricerca di discendenti diretti dell'elemento
  • Si consiglia di tirare tutte i valori in una volta e li converte in un dizionario
  • Se stai usando diversi tipi di dati per i contenuti , si potrebbe voler castare l'elemento invece di usare .Value
  • Si consiglia di creare un metodo per restituire l'abbinamento XElement per un determinato tipo, anziché avere più query.

Personalmente non penso che utilizzerei nemmeno un'espressione di query per questo. Per esempio:

static XElement FindParameter(XElement element, string type) 
{ 
    return element.Elements("parameter") 
        .SingleOrDefault(p => (string) p.Attribute("type") == type); 
} 

Poi:

var mydata = from item in document.Root.Elements("item") 
      select new { 
       Label = (string) item.Element("label"), 
       Description = (string) item.Element("description"), 
       Id = (int) FindParameter(item, "id"), 
       Name = (string) FindParameter(item, "name"), 
       Zip = (string) FindParameter(item, "zip") 
      }; 

Ho il sospetto che ci si accorge che è più ordinato rispetto a qualsiasi alternativa utilizzando XPath, supponendo che ho capito quello che stai cercando di fare.

+0

sì, sembra un buon approccio Jon ... l'altro problema che devo affrontare è che a volte i valori sono stringhe vuote, quindi avere un metodo di supporto per gestire sia la query di attributo che gestire con garbo il cast nel tipo corretto nel l'evento di stringhe vuote potrebbe essere più sensato, grazie – snappymcsnap

7

uso XPATH - è molto veloce (tranne xmlreader - ma un sacco di se di)

using (var stream = new StringReader(xml)) 
    { 
    XDocument xmlFile = XDocument.Load(stream); 

    var query = (IEnumerable)xmlFile.XPathEvaluate("/data/item/parameter[@type='id']"); 

    foreach (var x in query.Cast<XElement>()) 
    { 
     Console.WriteLine( x.Value); 
    } 

    } 
+7

quindi xpath è più veloce rispetto ai metodi LINQ incorporati? – snappymcsnap

+1

Una domanda sfortunata a cui non è mai stata data una risposta! –

Problemi correlati