tags:

views:

612

answers:

1

I'm new to both C# and Linq. I'm attempting to use a Linq-generated element collection to iterate over and modify certain elements in a XDocument. My understanding is that the enumeration does not update when the tree is updated.

For example, given the document

<root xmlns:ns="http://dummy"&gt;
<ns:a/>
<ns:b/>
<c/>
<ns:a><ns:a/></ns:a>
</root>

and the code

XDocument doc = XDocument.Load(@"test_input.xml", LoadOptions.PreserveWhitespace);
XNamespace ns = "http://dummy";

IEnumerable<XElement> elem_list = from elem in doc.Descendants()
                                  where elem.Name.Namespace == ns
                                  select elem;

foreach (XElement elem in elem_list) {
   if (elem.Name.LocalName == "a") {
      elem.Remove();
   }
}

gives an error because (I think) the nested "a" element is removed from the tree, but is still "present" in elem_list.

How do I get around this, keeping in mind that (1) the actual manipulations that I want to do involve more complex operations (i.e., copying) on the tree than the above example, and (2) I'm working with mixed content with significant whitespace? Does one of the other .Net XML document classes have a way to iterate that is updated as the tree changes?

+1  A: 

Usually, enumerators can't continue running when the collection is changed. However, if you use ToArray() or ToList() on them, the entire collection of results would be in a static list. Then, you can enumerable over the list, and removing them (from the document, not from the list) would not matter.

XDocument doc = XDocument.Load(@"test_input.xml", LoadOptions.PreserveWhitespace);
XNamespace ns = "http://dummy";

IEnumerable<XElement> elem_list = from elem in doc.Descendants()
                                  where elem.Name.Namespace == ns
                                  select elem;

XElement[] elem_array = elem_list.ToArray();

foreach (XElement elem in elem_array) {
   if (elem.Name.LocalName == "a") {
      elem.Remove();
   }
}
configurator