tags:

views:

594

answers:

2

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>
    </Parent>
</Parents>

Requirement -

  1. 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").
  2. 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?

+1  A: 

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");
Mehdi Golchin
+2  A: 

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.

David in Dakota