Ich hatte letztens ein XML-Dokument, welches ich etwas verschlanken wollte. Das Format war in etwa folgendes:

<root>
  <node1>Content</node1>
  <node2>Content</node2>
  <node3>Content</node3>
  <node4>Content</node4>
</root>

Ich wollte nur die “node1″ – Node behalten, sprich alle anderen entfernen. Daher mein erster Ansatz:

XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml("<root><node1>Content</node1><node2>Content</node2><node3>Content</node3><node4>Content</node4></root>");
XPathNavigator navigator = xmlDocument.CreateNavigator();
			
string[] nodesToRemove = new[] {"//node2", "//node3", "//node4"};

foreach (var nodeName in nodesToRemove)
{
	XPathNavigator node = navigator.SelectSingleNode(nodeName);
	if (node != null)
	{
		node.DeleteSelf();
	}
}

Console.WriteLine(xmlDocument.OuterXml);

Funktioniert und gut.

Nun wollte ich den Ansatz umdrehen, und alle Nodes entfernen, die nicht den Namen “node1″ haben.

XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml("<root><node1>Content</node1><node2>Content</node2><node3>Content</node3><node4>Content</node4></root>");
XPathNavigator navigator = xmlDocument.CreateNavigator();

string xpath = "/root/node()[name()!='node1']";

XPathNodeIterator nodes = navigator.Select(xpath);
while(nodes.MoveNext())
{
	if(nodes.Current != null)
	{
		nodes.Current.DeleteSelf();
	}
}

Console.WriteLine(xmlDocument.OuterXml);

Leider war das Ergebnis nicht so wie erwartet, obwohl der XPath korrekt ist und die anderen Nodes selektiert. Es wurde nur “node2″ gelöscht, sprich die erste Node, welche mit dem NodeIterator angesprochen wird. Durch das DeleteSelf() liefert MoveNext() automatisch false zurück, wenn es wieder aufgerufen wird. Ähnliche Probleme gibt es etwa auch, wenn in einer foreach()-Schleife der Enumerator geändert wird. Eine mögliche Lösung wäre folgendes:

while(nodes.MoveNext())
{
	if(nodes.Current != null)
	{
		nodes.Current.DeleteSelf();
		nodes = navigator.Select(xpath);
	}
}

Nach dem Löschen wird der XPath einfach noch mal ausgeführt. Meiner Meinung nach keine wirklich schöne Lösung, leider aber die einzige die ich gefunden habe, welche auch funktioniert.