Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delete multiple XML nodes in C# using Linq

Tags:

c#

.net

xml

linq

I'm trying to remove multiple nodes that a particular element(path) contains a value but I'm receiving a System.NullReferenceException any help where I'm going wrong would I'be much appreciated.

My xml looks like this:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<ApplicationData Version="12.5.1" RootPath="FireFox-FILES">
  <RegistrySystem>
    <DIR Operation="+" Path="C:\Temp\Microsoft\MediaPlayer\ShimInclusionList" />
    <DIR Operation="+" Path="C:\Temp\MediaPlayer\ShimInclusionList\MM.EXE" />
    <DIR Operation="+" Path="C:\Temp\MediaPlayer\ShimInclusionList\plugin-container.exe" />
    <DIR Operation="+" Path="C:\Temp\Microsoft\MediaPlayer">
      <ENTRY Name="" Value="43.0.4" Type="1" />
      <ENTRY Name="CurrentVersion" Value="43.0.4 (x86 en-GB)" Type="1" />
    </DIR>
    <DIR Operation="+" Path="C:\Program Files\Microsoft\MediaPlayer\ShimInclusionList\plugin-container.exe" />
    <DIR Operation="+" Path="C:\Program Files\Microsoft\MediaPlayer\ShimInclusionList2\plugin.exe" />
    <DIR Operation="+" Path="C:\Program Files\Microsoft\MediaPlayer\ShimInclusionList2\container.exe" />
    <DIR Operation="+" Path="C:\Program Files\Microsoft\MediaPlayer\ShimInclusionList4">
      <ENTRY Name="" Value="43.0.4" Type="1" />
      <ENTRY Name="CurrentVersion" Value="43.0.4 (x86 en-GB)" Type="1" />
    </DIR>
  </RegistrySystem>
</ApplicationData>

My code looks like this:

XDocument xdoc = XDocument.Load(XmlFile);
foreach (var node in xdoc.Descendants("DIR").Where(status => status.Attribute("Path").Value.Contains(@"C:\Temp\")))
{
    node.Remove();

}
xdoc.Save(XmlFile);

I'm not sure where I'm going wrong.

like image 639
BillyDay Avatar asked Mar 02 '16 09:03

BillyDay


1 Answers

I'm not sure why you're getting the exception, but I strongly suspect it's because you're modifying the document while you're querying it.

If you change your code to use a ToList() call to get the list of nodes to remove, that doesn't throw:

foreach (var node in xdoc.Descendants("DIR")
           .Where(status => status.Attribute("Path").Value.Contains(@"C:\Temp\"))
           .ToList())
{                                                                            
    node.Remove();
}

However, that's not the best way. The best approach is to use the Remove(this IEnumerable<XElement>) extension method:

xdoc.Descendants("DIR")
    .Where(status => status.Attribute("Path").Value.Contains(@"C:\Temp\"))
    .Remove();

No need for a foreach loop at all. Now to make it robust in the face of DIR elements without a Path attribute, you can cast to string instead:

xdoc.Descendants("DIR")
    .Where(status => ((string) status.Attribute("Path") ?? "").Contains(@"C:\Temp\"))
    .Remove();
like image 104
Jon Skeet Avatar answered Sep 24 '22 14:09

Jon Skeet