MasterDNE
MasterDNE

Reputation: 67

Edit multiple descendants of an element using Linq

I'm trying to see how I can edit multiple descendant elements of an element using LINQ. When I try and do it I am able to change the value of the first element succesfully but I am unable to do so on the second as it throws the following error:

System.NullReferenceException: 'Object reference not set to an instance of an object.'

I have the following in my xml doc:

<?xml version="1.0" encoding="utf-16"?>
<TestCases>
  <TestCase>
    <name>one</name>
    <ticket>biscuit</ticket>
    <summary>ok</summary>
    <prerequisites>ok</prerequisites>
  </TestCase>
  <TestCase>
    <name>two</name>
    <ticket>biscuits</ticket>
    <summary>ok</summary>
    <prerequisites>ok</prerequisites>
  </TestCase>
</TestCases>

And here is my code:

XDocument doc = XDocument.Load(@"C:\Users\Dani\source\repos\Test Cases\testCaseList.xml");

var q = from node in doc.Descendants("TestCase")
        where node.Element("name").Value == uneditedTestCase.name
        select node;

q.Descendants("name").SingleOrDefault().SetValue(Form1.currentTestCase.name);
q.Descendants("ticket").SingleOrDefault().SetValue(Form1.currentTestCase.ticket);

doc.Save(@"C:\Users\Dani\source\repos\Test Cases\testCaseList.xml");

Upvotes: 1

Views: 114

Answers (1)

Saeb Amini
Saeb Amini

Reputation: 24419

LINQ queries are executed lazily, at the point you enumerate them. And every time you enumerate them, if the source data/collection has changed, the results could be different.

You need to eagerly materialise your query into a collection (e.g. via ToList) before modifying the elements:

var q = (from node in doc.Descendants("TestCase")
        where node.Element("name").Value == uneditedTestCase.name
        select node).ToList();

Otherwise when you execute

q.Descendants("name").SingleOrDefault().SetValue(Form1.currentTestCase.name);

You are changing the name, which makes your original query not have any matches (where node.Element("name").Value == uneditedTestCase.name1 would no longer be true for any elements)

Therefore the second time you execute your query, the below will be null:

q.Descendants("ticket").SingleOrDefault()

And calling SetValue on null gives you a NullReferenceException.

Upvotes: 3

Related Questions