Reputation: 607
I have a piece of xml like the following:
<Table>
<Record>
<Field>Value1_1</Field>
<Field>Value1_2</Field>
</Record>
<Record>
<Field>Value2_1</Field>
<Field>Value2_2</Field>
</Record>
</Table>
What i would like is a LINQ query that generates an IEnumerable that i can assign as the datasource of a DataGrid. What i have so far is as follows:
var temp = from record in table.Elements("Record")
select record.Element("Field").Value
The fact that I can have multiple field elements is my stumbling block.
In the above example, what i need is something like an IEnumerable<string,string>
.
The datagrid would look something like this:
Value1_1, Value1_2
Value2_1, Value2_2
Upvotes: 9
Views: 61534
Reputation: 11
Maybe this?
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);
}
}
Upvotes: 1
Reputation:
I don't get what the problem is and why a number of these answers look so complicated :-/ Here is my offering:
var r = (from record in table.Elements("Record")
select (from element in record.Elements("Field")
select element.Value));
// => IEnumerable<IEnumerable<string>>
The inner IEnumerable is for the columns and the outer is for the rows. (The question is kind of confusing because there is no IEnumerable<T,T'>
, the above is my adaptation of the intent.)
You could make the inner IEnumerable into a string (e.g. Join on ", "), but that's not very fun to put into a grid if you mean the values as columns!
var r = (from record in table.Elements("Record")
select String.Join(", ",
record.Elements("Field").Select(f => f.Value).ToArray());
// => IEnumerable<string>
The above could likely be made nicer if I actually knew LINQ Expressions. However, it works and covers the "other" case -- the "ToArray" is for .NET 3.5 and below.
Upvotes: 1
Reputation: 1
var detail1 = from d in ds.tbl_Looking_Fors where d.Profile_ID == id select d.Looking_For ;
string[] datum = detail1.ToArray();
if (datum != null && datum.Length > 0)
{
foreach (var row in datum)
{
Label6.Text = datum[0]+" , "+datum[1];
}
}
Upvotes: 0
Reputation: 4584
Would an
IEnumerable<List<string>>
work? (not sure how to get that to display inline)
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();
Don't know if that works for your specific scenario or not.
Upvotes: 0
Reputation: 39836
Er... I think you're using the wrong LINQ paradigm for this problem. You should be using LINQ to XML which is slightly different maybe than you're expecting.
Check out this link:
http://msdn.microsoft.com/en-us/library/bb308960.aspx
It explains it using a structurally similar example to the one you presented.
Upvotes: 0
Reputation: 2488
I may be way off in what you're looking for, but are you looking for something like this?
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);
}
}
Then return ds
and set the DataMember
to "Records"
Upvotes: 0
Reputation: 1837
You need a 2-step processs:
Annotate the records (in lieu of attributes) and then Enumerate the fields and pass the values into an anonymous class for binding, like so:
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);
}
}
Upvotes: 0
Reputation: 6950
It sounds like you want to denormalize the field so that it fits in 1 column in your data grid.
Does the following help?
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: I don't do much SQL or LINQ anymore, so this probably could be made better. Feel free to change it.
Upvotes: 4
Reputation: 7681
Would something like this help?
var a = from record in table.Elements("Record")
select new
{
one = (string)record.Elements().ElementAt(0),
two = (string)record.Elements().ElementAt(1)
};
Upvotes: 11
Reputation: 7378
You can chain calls to Elements()
:
var temp = from field in table.Elements("Record").Elements("Field")
select field.Value;
You can also use Descendants()
:
var temp = from field in table.Descendants("Field")
select field.Value;
However, this will return all <Field> elements under <Table>, even if they are not within a <Record> element.
Upvotes: 0