I have an XML file that will be similar to the structure below:
<?xml version="1.0" encoding="utf-8"?>
<Root Attr1="Foo" Name="MyName" Attr2="Bar" >
<Parent1 Name="IS">
<Child1 Name="Kronos1">
<GrandChild1 Name="Word_1"/>
<GrandChild2 Name="Word_2"/>
<GrandChild3 Name="Word_3"/>
<GrandChild4 Name="Word_4"/>
</Child1>
<Child2 Name="Kronos2">
<GrandChild1 Name="Word_1"/>
<GrandChild2 Name="Word_2"/>
<GrandChild3 Name="Word_3"/>
<GrandChild4 Name="Word_4"/>
</Child2>
</Parent1>
</Root>
The elements are not defined in that they can have different values than other files. What I do know is the “Name” attribute of each element before hand, which will always be defined. I need to be able to manipulate, and/or delete data within a selected element based on that name. For Example: removeElement("MyName.IS.Kronos1.Word_1") would delete the GrandChild1 element underneath the Child1 Parent.
My issues is that while using LINQ to XML queries I’m not able to select that element properly. Using this:
private IEnumerable<XElement> findElements(IEnumerable<XElement> docElements, string[] names)
{
// the string[] is an array from the desired element to be removed.
// i.e. My.Name.IS ==> array[ "My, "Name", "IS"]
IEnumerable<XElement> currentSelection = docElements.Descendants();
foreach (string name in names)
{
currentSelection =
from el in currentSelection
where el.Attribute("Name").Value == name
select el;
}
return currentSelection;
}
To find where I need to remove the elements yields this result:
<?xml version="1.0" encoding="utf-8"?>
<Root Attr1="Foo" Name="MyName" Attr2="Bar" >
<Parent1 Name="IS">
<Child1 Name="Kronos1">
<GrandChild2 Name="Word_2"/>
<GrandChild3 Name="Word_3"/>
<GrandChild4 Name="Word_4"/>
</Child1>
<Child2 Name="Kronos2">
<GrandChild2 Name="Word_2"/>
<GrandChild3 Name="Word_3"/>
<GrandChild4 Name="Word_4"/>
</Child2>
</Parent1>
</Root>
After debugging it appears that all I’m doing is searching for the same document over again, but for different names each time. How do I search and select a specific element based on multiple parent attribute Names?
It should be noted, that the size of the XML (meaning levels of elements) are also variable. Meaning that there can as little as 2 levels (Parents) or up to 6 levels (Great-Great-GrandChildren). However, I NEED to be able to look at the root node’s Name Attribute as well.
This should work:
You can replace the latest lines by the following if you want to:
The
.First()method throws an exception if no matching element is found in source.The cleanest approach would be to add a new function:
Such that you can simply use it as following:
And then, if you ever need to select one child, you have a handy
SelectChildElement()avaialble. If you want to domyElement.SelectChild(child)instead, you can call it from an extension.Also, as you use FirstOrDefault here, you don’t get an exception but get
nullreturned instead.This way, it doesn’t have to keep track of exceptions which is often more costly…