2009-05-20 17 views
8

Ho un pezzo di XML come la seguente:Come utilizzare una query LINQ per ottenere i valori XElement quando XElements hanno stesso nome

<Table> 
    <Record> 
    <Field>Value1_1</Field> 
    <Field>Value1_2</Field> 
    </Record> 
    <Record> 
    <Field>Value2_1</Field> 
    <Field>Value2_2</Field> 
    </Record> 
</Table> 

Quello che vorrei è una query LINQ che genera un IEnumerable che posso assegnare come origine dati di un DataGrid. Quello che ho finora è il seguente:

var temp = from record in table.Elements("Record") 
      select record.Element("Field").Value 

Il fatto che io possa avere più elementi di campo è il mio scoglio.

Nell'esempio precedente, ciò di cui ho bisogno è qualcosa come un IEnumerable<string,string>. Il datagrid sarebbe simile a questa:

Value1_1, Value1_2 
Value2_1, Value2_2 
+0

L'XML è un po 'strano possiamo assumere che ogni elemento di campo all'interno di un record sia in effetti un nome univoco. Sicuramente non sono tutti chiamati "Field"? – AnthonyWJones

+0

Qual è il tuo comportamento previsto? Cioè dato che ci sono più elementi Field, quale vuoi? – DSO

+0

L'xml è abbastanza strano, ma sfortunatamente sono bloccato con esso. – JohnC

risposta

0

Puoi chiamate chain per Elements():

var temp = from field in table.Elements("Record").Elements("Field") 
      select field.Value; 

È anche possibile utilizzare Descendants():

var temp = from field in table.Descendants("Field") 
      select field.Value; 

Tuttavia, questo tornerà tutto < Campo> elementi nella tabella <>, anche se non si trovano all'interno di un elemento Record> <.

8

Sarebbe qualcosa di simile aiuto?

var a = from record in table.Elements("Record") 
    select new 
    { 
     one = (string)record.Elements().ElementAt(0), 
     two = (string)record.Elements().ElementAt(1) 
    }; 
+0

Concordato - Penso che questa sia la sua unica opzione data che l'ordine di loro è importante. Potrebbe essere migliorato (più preciso) inserendo "Field" nella chiamata a Elements() vuota. – TheSoftwareJedi

+0

Esattamente quello che stavo cercando quando questa domanda è arrivata nella mia ricerca, ho creato la taglia per premiarti per questo dato che non sembra che il richiedente avrebbe accettato ... –

3

Sembra che si desidera denormalizzare campo in modo che si adatti in 1 colonna nella griglia di dati.

Il seguente aiuto?

var table = XElement.Parse(@"<Table> 
           <Record><Field>Value1_1</Field><Field>Value1_2</Field></Record> 
           <Record><Field>Value2_1</Field><Field>Value2_2</Field></Record> 
          </Table>"); 


var temp = from record in table.Elements("Record") 
      from field in record.Elements("Field") 
      group field.Value by record into groupedFields 
      select groupedFields.Aggregate((l, r) => l + ", " + r); 

foreach (var row in temp) 
    Console.WriteLine(row); 

Console.ReadKey(); 

Disclaimer: Non faccio molto SQL o LINQ più, quindi questo probabilmente potrebbe essere fatto meglio. Sentiti libero di cambiarlo.

0

Posso essere fuori strada in quello che stai cercando, ma stai cercando qualcosa di simile?

 DataSet ds = new DataSet("Records DS"); 
     ds.Tables.Add("Records"); 
     foreach (XElement record in table.Descendants("Record")) 
     { 
      var temp = from r in record.Descendants("Field") 
         select r.Value; 

      string[] datum = temp.ToArray(); 
      if (datum != null 
       && datum.Length > 0) 
      { 
       foreach (string s in datum) 
        ds.Tables[0].Columns.Add(); 
       DataRow row = ds.Tables[0].NewRow(); 
       row.ItemArray = datum; 
       ds.Tables[0].Rows.Add(row); 
      } 
     } 

Poi ritorno ds e impostare il DataMember a "Records"

0

Hai bisogno di una processs 2-step:

Annota i record (in sostituzione di attributi) e poi enumerare i campi e passare i valori in una classe anonima per il binding, in questo modo:

string xml = [string-goes-here]; 

    XElement elem = XElement.Parse(xml); 

    int count= 0; 
    foreach(XElement recordElems in elem.Elements("Record")){ 
    recordElems.SetAttributeValue("id", count); 
    count++; 
    } 
    var temp = from record in elem.Elements("Record") 
      from field in record.Elements("Field") 
      select new { Record = "Record " + record.Attribute("id").Value, Field = field.Value }; 

    foreach (var item in temp) 
    { 
    Console.WriteLine("{0}: {1}", item.Record, item.Field); 
    } 
} 
0

Er ... I t stai usando il paradigma LINQ sbagliato per questo problema. Dovresti usare LINQ in XML che è leggermente diverso forse di quanto ti aspetti.

controlla questo link:

http://msdn.microsoft.com/en-us/library/bb308960.aspx

E lo spiega con un esempio strutturalmente simile a quello che hai presentato.

0

Sarebbe un'opera

IEnumerable<List<string>> 

? (Non so come ottenere che per visualizzare in linea)

var recordList = from record in data.Elements("record") select record; 
List<List<string>> x = new List<List<string>>(recordList.Count()); 
foreach (var record in recordList) 
{ 
    var z = from field in record.Elements("field") select field.Value; 
    x.Add(z.ToList()); 
} 
return x.AsEnumerable(); 

Non so se funziona per lo scenario o meno specifici.

0

var detail1 = da d in ds.tbl_Looking_Fors dove d.Profile_ID == id selezionare d.Looking_For;

  string[] datum = detail1.ToArray(); 
      if (datum != null && datum.Length > 0) 
      { 
       foreach (var row in datum) 
       { 
        Label6.Text = datum[0]+" , "+datum[1]; 
       } 

      } 
1

Non capisco quale sia il problema e perché un certo numero di queste risposte sembra così complicato: -/Ecco la mia offerta:

var r = (from record in table.Elements("Record") 
     select (from element in record.Elements("Field") 
       select element.Value)); 

// => IEnumerable<IEnumerable<string>> 

Il IEnumerable interna è per le colonne e la l'esterno è per le file. (La domanda è un po 'confusa perché non c'è IEnumerable<T,T'>, il precedente è il mio adattamento dell'intento.)

Si potrebbe rendere l'IEnumerable interno in una stringa (ad esempio Join on ","), ma non è molto divertente mettere in una griglia se intendi i valori come colonne!

var r = (from record in table.Elements("Record") 
     select String.Join(", ", 
      record.Elements("Field").Select(f => f.Value).ToArray()); 

// => IEnumerable<string> 

Quanto sopra potrebbe essere reso più bello se conoscessi effettivamente le espressioni LINQ. Tuttavia, funziona e copre il caso "altro" - il "ToArray" è per .NET 3.5 e versioni successive.

1

Forse questo?

using System.Linq; 
using System.Xml.Linq; 
using System.Collections.Generic; 
using System.Diagnostics; 

[TestMethod] 
    public void Linq_XElement_Test() 
    { 


    string xml = @"<Table> 
    <Record> 
    <Field>Value1_1</Field> 
    <Field>Value1_2</Field> 
    </Record> 
    <Record> 
    <Field>Value2_1</Field> 
    <Field>Value2_2</Field> 
    </Record> 
</Table>"; 

    XElement elements = XElement.Parse(xml); 

    var qryRecords = from record in elements.Elements("Record") 
        select record; 

    foreach (var rec in qryRecords) 
    { 
     Debug.WriteLine(rec.Value); 
    } 

    var qryFields = from record in elements.Elements("Record") 
       from fields in record.Elements("Field") 
       select fields; 

    foreach (var fil in qryFields) 
    { 
     Debug.WriteLine(fil.Value); 
    } 

    IEnumerable<string> list = qryFields.Select(x => x.Value); 

    foreach (string item in list) 
    { 
     Debug.WriteLine(item); 
    } 


} 
+0

Per favore, indica cosa fa il tuo codice postato risolvere il problema. Il tuo codice può essere d'aiuto, ma affermare ciò che fa può aiutare le altre persone a capire e imparare da esso. – Joel

Problemi correlati