Fetching descendant nodes always return null XML C#

I have an XML file that looks like this

<modules>
<level4>
<module>
  <name>Programming Principles I</name>
  <credit>20</credit>
  <assessments>

    <assessment>
      <assessment_name>Course Work 1</assessment_name>
      <weight>50</weight>
      <passing>55</passing>
      <obtain>55</obtain>
    </assessment>
    <assessment>
      <assessment_name>Course Work 2</assessment_name>
      <weight>50</weight>
      <passing>55</passing>
      <obtain>55</obtain>
    </assessment>

  </assessments>
</module>
</level4>
</modules>

Whilst, getting into assessment childs of parent assessments it returns null..

using this code

XDocument xml = XDocument.Load("module.xml");
var result = xml.Descendants("module")
                         .FirstOrDefault(x => (string)x.Element("name") == "Programming Principles I");
var assessments = result.Element("assessments");
var assessment = assessments.Descendants("assessment");
foreach(var a in assessment)
{
    a.Remove();
}

At this assessment variable I am getting null value exception. The LINQ query works fine but the next two lines I am uncertain. I am actually, removing all the nodes present inside assessments node.

Jon Skeet
people
quotationmark

Modifying a lazily-evaluated query while iterating over it is basically dangerous.

Two options:

  • Use the Remove extension method. Less code, and it'll work! Replace your whole loop with:

    assessment.Remove();
    
  • Evaluate the query before you start removing anything, storing the result as a list. At this point, it's fine to use foreach because removing the element from its parent won't remove it from the list:

    foreach(var a in assessment.ToList())
    {
        a.Remove();
    }
    

You still have a problem in your code though - you're using FirstOrDefault() when finding the module element, which means you're anticipating that you might not find it - but you're ignoring that possibility in the next line.

I'd probably rewrite the code to this:

var assessmentsToRemove = xml
    .Descendants("module")
    .Where(mod => (string) mod.Element("name") == "Programming Principles I")
    .Elements("assessments")
    .Elements("assessment");
assessmentsToRemove.Remove();

You could do it all in a single statement if you want, but the above approach makes it easier to diagnose issues later in the debugger.

people

See more on this question at Stackoverflow