I was wondering if anyone can help with the following:
I've got a xml document like this:
<div class="_cl">element description 1</div>
<div class="_cl">
<anotherele>dtls</anotherele>
<anotherele>moredtls</anotherele>
</div>
<div class="_cl">
<anotherele>dtls</anotherele>
<anotherele>moredtls</anotherele>
</div>
<div class="_cl">element description 2</div>
<div class="_cl">
<anotherele>dtls</anotherele>
<anotherele>moredtls</anotherele>
</div>
<div class="_cl">
<anotherele>dtls</anotherele>
<anotherele>moredtls</anotherele>
</div>
I was wondering if there was any way in linq to group this by elements that don't have child elements. Basically, trying to structure the document somehow like this:
<div class="_cl">element description 1
<div class="_cl">
<anotherele>dtls</anotherele>
<anotherele>moredtls</anotherele>
</div>
<div class="_cl">
<anotherele>dtls</anotherele>
<anotherele>moredtls</anotherele>
</div>
</div>
<div class="_cl">element description 2
<div class="_cl">
<anotherele>dtls</anotherele>
<anotherele>moredtls</anotherele>
</div>
<div class="_cl">
<anotherele>dtls</anotherele>
<anotherele>moredtls</anotherele>
</div>
</div>
My first woeful attempt looks like this:
var n = from a in doc.Descendants()
where a.Name.LocalName == "div" && (string)a.Attribute("class") == "_cl"
group a by a.Value.Length<50 into g
select new { k = g.Key, p = g.Count() };
Hope this makes sense and thanks in advance.
Stu
Here is an example, assuming the input is
<body>
<div class="_cl">element description 1</div>
<div class="_cl">
<anotherele>dtls</anotherele>
<anotherele>moredtls</anotherele>
</div>
<div class="_cl">
<anotherele>dtls</anotherele>
<anotherele>moredtls</anotherele>
</div>
<div class="_cl">element description 2</div>
<div class="_cl">
<anotherele>dtls</anotherele>
<anotherele>moredtls</anotherele>
</div>
<div class="_cl">
<anotherele>dtls</anotherele>
<anotherele>moredtls</anotherele>
</div>
</body>
then the code
XDocument input = XDocument.Load("input.xml");
XDocument output = new XDocument(
new XElement(input.Root.Name,
from el in input.Root.Elements()
where el.Elements().Any()
group el by el.NodesBeforeSelf().OfType<XElement>().LastOrDefault(e => !e.Elements().Any()) into g
select new XElement(g.Key.Name,
g.Key.Attributes(),
g.Key.Nodes(),
g)
));
output.Save(Console.Out);
outputs
<body>
<div class="_cl">element description 1<div class="_cl"><anotherele>dtls</anoth
erele><anotherele>moredtls</anotherele></div><div class="_cl"><anotherele>dtls</anotherele><anotherele>moredtls</anotherele></div></div>
<div class="_cl">element description 2<div class="_cl"><anotherele>dtls</anoth
erele><anotherele>moredtls</anotherele></div><div class="_cl"><anotherele>dtls</anotherele><anotherele>moredtls</anotherele></div></div>
</body>
This is what you want I think, with the exception of the indentation. As for the indentation, you might get closer to your desired result by loading the input with XDocument.Load("input.xml", LoadOptions.PreserveWhitespace)
.
For more on this grouping approach, see http://msmvps.com/blogs/martin_honnen/archive/2009/11/27/grouping-with-linq-to-xml.aspx .
Svarog is right; what you're trying to do can't be achieved by grouping. You'd need some more advanced Linq expressions than are given in the Linq keywords.
Try this:
var n = doc.Elements().Where(div=>!div.Elements().Any()).
Select(div=>{
div.Add(
div.ElementsAfterSelf().TakeWhile(x=>x.Elements().Any())
);
return div;
});
Thanks for your input, but none of the solutions seem to quite cut it. I think what I'll do is just loop through the elements and parse it manually. I just thought a nice linq one-liner would be better.
Cheers
Stu
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.