I am constructing some XML using Linq to object and have managed to get what I want using code similar to the following example. I can't help feeling that it could be better though. What really bothers me is the "illustrations" node where I have to join the group back to the original data.
You can see what I'm trying to do by running the query (I've used Linqpad). There's a list of pages, some which have illustrations. I want to list all pages with the illustrations if there are any.
Any comments please..?
var illustrations = new []
{
new {page = 1, illustration= "a"},
new {page = 2, illustration = "b"},
new {page = 1, illustration = "c"}
};
var pages = new []
{
new {page = 1, pageName = "w"},
new {page = 2, pageName = "x"},
new {page = 3, pageName = "y"},
new {page = 4, pageName = "z"}
};
var x1 = new XElement("contents",
from page in pages join illustration in illustrations on page.page equals illustration.page
into pagesIllustrations from pr in pagesIllustrations.DefaultIfEmpty() //Left outer join
group page by page.page into g
select new XElement("content",
new XAttribute("contentPageName", g.First().pageName),
new XElement("pages",
from o1 in g.Distinct()
select new XElement("page",
new XAttribute("PageNumber", o1.page),
new XAttribute("PageName", o1.pageName))),
new XElement("illustrations",
from o2 in g.Distinct() join i in illustrations on o2.page equals i.page
select new XElement("illustration",
new XAttribute("PageNumber", i.page),
new XAttribute("IllustrationName", i.illustration)))));
x1.Dump();
Here's the xml I'm producing. It is exactly as I want it to be, I just can't help feeling I'm not doing it the best way.
<contents>
<content contentFileName="w">
<pages>
<page PageNumber="1" PageName="w" />
</pages>
<resources>
<resource PageNumber="1" ResourceName="a" />
<resource PageNumber="1" ResourceName="c" />
</resources>
</content>
<content contentFileName="x">
<pages>
<page PageNumber="2" PageName="x" />
</pages>
<resources>
<resource PageNumber="2" ResourceName="b" />
</resources>
</content>
<content contentFileName="y">
<pages>
<page PageNumber="3" PageName="y" />
</pages>
<resources />
</content>
<content contentFileName="z">
<pages>
<page PageNumber="4" PageName="z" />
</pages>
<resources />
</content>
</contents>