views:

494

answers:

1

Greetings!

I have an XElement object that contains the following:

<Root>
    <SubSections>
        <SubSection id="A">
            <Foo id="1">
                <Bar />
                <Bar />
                <Bar />
            </Foo>
            <Foo id="2">
                <Bar />
                <Bar />
            </Foo>
            <Foo id="3">
                <Bar />
            </Foo>
        </SubSection>
        <SubSection id="B">
            <Foo id="4">
                <Bar />
                <Bar />
                <Bar />
            </Foo>
            <Foo id="5">
                <Bar />
                <Bar />
            </Foo>
         </SubSection>
        <SubSection id="C">

        </SubSection>
    </SubSections>
</Root>

I'd like to move Foo's 2 and 3 to the SubSection with the id of "C" such that the result is:

<Root>
    <SubSections>
        <SubSection id="A">
            <Foo id="1">
                <Bar />
                <Bar />
                <Bar />
            </Foo>
        </SubSection>
        <SubSection id="B">
            <Foo id="4">
                <Bar />
                <Bar />
                <Bar />
            </Foo>
            <Foo id="5">
                <Bar />
                <Bar />
            </Foo>
        </SubSection>
        <SubSection id="C">
            <Foo id="2">
                <Bar />
                <Bar />
            </Foo>
            <Foo id="3">
                <Bar />
            </Foo>
        </SubSection>
    </SubSections>
</Root>

What's the best way to go about moving Foo sections "2" and "3" to the "C" SubSection?

+2  A: 

You need to get Foo sections 2 and 3 with a query like:

var foos = from xelem in root.Descendants("Foo")
           where xelem.Attribute("id").Value == "2" || xelem.Attribute("id").Value == "3"
           select xelem;

And then iterate that list and remove them from their parents with

xelem.Remove();

Then just add them to the correct node with:

parentElem.Add(xelem);

The first query will get you both sections then remove and add each one to the correct place on the tree.

Here's a complete solution:

var foos = (from xElem in xDoc.Root.Descendants("Foo")
                   where xElem.Attribute("id").Value == "2" || xElem.Attribute("id").Value == "3"
                   select xElem).ToList();

        var newParentElem = (from xElem in xDoc.Root.Descendants("SubSection")
                            where xElem.Attribute("id").Value == "C"
                            select xElem).Single();

        foreach(var xElem in foos)
        {
            xElem.Remove();
            newParentElem.Add(xElem);
        }

After that your xDoc should have the correct tree.

Stephan
A few minor comments: .Value is a string so quote the "2" and "3". I believe you can just call foos.Remove() instead of iterating. Though you may need to copy the foos before then since .Remove() cleans foos up.
Richard Morgan
You are probably right. I imagine you could probably just call foos.Remove() followed by parentElem.Add(foos) but I figured it'd be better to iterate and then you can remove and then add that element, and then move the IEnumerable to the next element.
Stephan
This results in an empty parentElem node:var toMove = foos;foos.Remove();parentElem.Add(toMove);And this kills the web server (probably because it keeps adding and removing the same node over and over):var toMove = foos;parentElem.Add(toMove);foos.Remove();Any ideas?
Bullines
var toMove = foos.ToList();
Richard Morgan
That did the trick :) Thanks.
Bullines
Iterating is probably safer, but I find it a challenge to never write a foreach statement again. :) Instead of the loop, try: newParentElem.Add(foos); foos.Remove();
Richard Morgan