You can group rows by product, and then group product's rows by their type:
var query = from r in table.AsEnumerable()
group r by r.Field<int>("productid") into g
let types = g.GroupBy(r => r.Field<int>("typenumber"))
select new {
productId = g.Key,
name = GetText(types.FirstOrDefault(t => t.Key == 0)),
shortdescription = GetText(types.FirstOrDefault(t => t.Key == 2)),
longdescription = GetText(types.FirstOrDefault(t => t.Key == 1))
};
Where helper method just orders type rows by line number and returns concatenated text
private static string GetText(IEnumerable<DataRow> rows)
{
if (rows == null)
return null;
var query = from r in rows
orderby r.Field<int>("linenumber")
select r.Field<string>("text");
return String.Join(" ", query);
}
Output:
[
{
productId: 100,
name: "this is the name of a1",
shortdescription: "this is the description of a1",
longdescription: null
},
{
productId: 200,
name: "this is the name of a2",
shortdescription: null,
longdescription: "shortdescription of a2"
}
]
You can build new DataTable manually or with this CopyToDataTable method. You also can build Xml with Linq to Xml:
var xdoc = new XDocument(new XElement("products",
from p in query
select new XElement("product",
new XAttribute("productId", p.productId),
new XElement("name", p.name),
new XElement("shortDescription", p.shortdescription),
new XElement("longDescription", p.longdescription))));
Output:
<products>
<product productId="100">
<name>this is the name of a1</name>
<shortDescription>this is the description of a1</shortDescription>
<longDescription />
</product>
<product productId="200">
<name>this is the name of a2</name>
<shortDescription />
<longDescription>shortdescription of a2</longDescription>
</product>
</products>
Or (maybe) simpler solution - instead of anonymous type usage, create custom class which can be easily serialized to xml.