Using LINQ to surround all "group" elements with the new element "groups" in C#
I'm new to LINQ and C# but I have an xml file generated from a database table. Within the XML document is a element called "group", I would like to wrap all group elements with the element called "groups".
An extract of the XML document is:
<members>
- <user>
<fullname>John Smith</fullname>
<username>SmithA</username>
<email>John.smith@test.com/email>
<distinguishedName>xxx</distinguishedName>
<group>London</group>
</user>
- <user>
<fullname>Sue Jones</fullname>
<username>JonesS</username>
<email>Sue.Jones@test.com/email>
<distinguishedName>xxx</distinguishedName>
<group>London</group>
</user>
</members>
The end result I struggling to code in C# ASP.NET is:
<members>
- <user>
<fullname>John Smith</fullname>
<username>SmithA</username>
<email>John.smith@test.com/email>
<distinguishedName>xxx</distinguishedName>
<groups>
<group>开发者_如何转开发;London</group>
<groups>
</user>
- <user>
<fullname>Sue Jones</fullname>
<username>JonesS</username>
<email>Sue.Jones@test.com/email>
<distinguishedName>xxx</distinguishedName>
<groups>
<group>London</group>
<groups>
</user>
</members>
Any help will be appreciated.
I think this is what you want - it seems to work for me:
using System;
using System.Linq;
using System.Xml.Linq;
class Program
{
static void Main(string[] args)
{
XDocument doc = XDocument.Load("test.xml");
var groupedGroups = doc.Descendants("group")
.GroupBy(x => x.Parent);
foreach (var groupedGroup in groupedGroups)
{
// Create the new element (copies each <group>)
groupedGroup.Key.Add(new XElement("groups", groupedGroup));
// Remove all the old ones
foreach (var element in groupedGroup)
{
element.Remove();
}
}
Console.WriteLine(doc);
}
}
Apologies for the name - it's kinda hard to come up with names when every concept is "group" :)
One way to do this is to:
- Go through each
user
element - Add the new
groups
element - Add the existing
group
to the newgroups
element - Remove the original
group
element
This approach would be similar to this, provided xml
is an XElement
:
foreach (var user in xml.Elements("user"))
{
user.Add(new XElement("groups", user.Element("group")));
user.Element("group").Remove();
}
If you're using an XDocument
you could use xml.Root.Elements("user")
instead.
EDIT: in response to your comment, if the XML contained multiple numbered groups you could filter on all elements that start with "group" and do almost the same thing.
foreach (var user in xml.Elements("user"))
{
var groups = user.Elements()
.Where(e => e.Name.LocalName.StartsWith("group"))
.ToArray();
// rename groups
foreach (var group in groups)
group.Name = "group";
user.Add(new XElement("groups", groups));
groups.Remove();
}
Notice that I used ToArray()
to prevent the Remove
call from reevaluating the expression, which would incorrectly remove the newly added groups
element since it too matches the condition of starting with "group." Another way around this would be to change the Where
predicate to also check that the name ends with a digit. It's extra work to prevent accidentally selecting any other element that may start with "group" but it's up to you based on your knowledge of the XML structure.
精彩评论