XML Traversing, Copy Elements and Nodes using LINQ to XML
My XML Document is as below -
<?xml version="1.0" encoding="utf-8"?>
<Parents>
<Parent id="A" description="A is a parent">
<Children>
<ChildName name = "Son1ofA" />
<ChildName name = "Son2ofA" />
</Children>
开发者_StackOverflow </Parent>
</Parents>
Requirement -
- To identify the Element "Parent", clone it. Change the attribute id to "B". Add it as a sibling to itself (making it a new child of "Parents").
The output file is as below -
<Parents> <Parent id="A" description="A is a parent"> <Children> <ChildName name = "Son" /> <ChildName name = "Daughter" /> </Children> </Parent> <Parent id="B" description="A is a parent"> <Children> <ChildName name = "Son" /> <ChildName name = "Daughter" /> </Children> </Parent>
My Code
XDocument myXMLDocument = XDocument.Load("File.xml");
XElement myParentsElement = myXMLDocument.Element("Parents");
XElement myFirstParentElement = myParentsElement.Element("Parent");
XElement myNewParentElement = new XElement(myFirstParentElement);
XAttribute myParentId = myNewParentElement.Attribute("id");
myParentId.Value = "B";
myFirstParentElement.AddAfterSelf(myNewParentElement);
myXMLDocument.Save("NewFile.xml");
And it works perfectly fine, without any issues. Clearly, this is no good programming. Because, I am extracting the Element Parents, then using that as a root node, I am extracting Parent etc.,
What I would want to be able to do is something like this - Directly key in the path - as in /Parents/Parent(XPath), extract that particular Node, make a copy of it, make modifications to its attributes, add it as a sibling and save the Document.
Am I doing something silly?
I wouldn't say you're doing something "silly" but there are ways to clone a node and modify it in a more streamlined way with LINQ. Depending on what your goals are, you can use a function to modify the node and some handy LINQ expressions to clone it. Here is an example based on what you've done above:
XDocument doc = XDocument.Parse(@"<?xml version='1.0' encoding='utf-8'?>
<Parents>
<Parent id='A' description='A is a parent'>
<Children>
<ChildName name = 'Son1ofA' />
<ChildName name = 'Son2ofA' />
</Children>
</Parent>
</Parents>
");
Func<XElement, XElement> trans = (x) => {
char c = Convert.ToChar(x.Attribute("id").Value);
int inc = (int)c;
x.Attribute("id").Value = Convert.ToChar(++inc).ToString();
return x;
};
string elementTarget = "Parent"; // assume you read this from some input
doc.Root.ReplaceWith(new XElement(doc.Root.Name,
doc.Descendants(elementTarget).Select(p => p),
doc.Descendants(elementTarget).Select(p => trans(p))));
Console.Write(doc);
Console.ReadLine();
You can see the logic for transforming in the "trans" anonymous function and the ability to arbitrarily select a node using the Descendants enumeration in LINQ. This solution is somewhat brittle but perhaps it can give you some ideas.
If you want to use XPath in Linq-to-xml, here are some extension methods that will be help.
using System.Xml.XPath;
XDocument.Load("file name").XPathSelectElement("XPath");
精彩评论