tags:

views:

215

answers:

3

Hi! I'm quite new to .NET and even more so to LINQ, which I have just begun exploring for a small project I'm working on.

I have a XML file generated from an application that contains a few values that I want to parse into a proprietary format and save in a file.

I'm able to make one LINQ query work fine, returning values to my Console app. Then the second query runs, also returns the requested values, but then throws a NRE! Why doesn't it stop iterating over the resultset after the third value has been returned?

First, heres an excerpt of the XML file:

<analyse>
   <sample>Leer 12</sample> sample ID and number
   <id>Leer</id>    sample ID
</analyse>
<results>
   <element>
     <name>c</name>
        <value>0.000186156337031958</value>
     </element>
   <element>
     <name>co2</name>
        <value>0.000682099902270885</value>
   </element>
   <element>
     <name>s</name>
        <value>0.000121750914950204</value>
   </element>
   <element>
     <name>so3</name>
        <value>0.000304028592755094</value>
   </element>
</results>

This is the first LINQ query:

XDocument uniSample = XDocument.Load(limsfile);

        var analyse = uniSample.Descendants("analyse").Select(el => new
                                                {
                                                    Sample = el.Element("sample").Value,
                                                    Id = el.Element("id").Value
                                                });

        foreach (var el in analyse)
        {
            Console.WriteLine("Sample: " + el.Sample);
            Console.WriteLine("Sample ID: " + el.Id);
        }

This is the second LINQ query: (note how I had to rename the anonynous type Value because it seemed to conflict with something)

var results = uniSample.Descendants("element").Select(elements => new 
                                                {
                                                    Name = elements.Element("name").Value,
                                                    Verdi = elements.Element("value").Value
                                                });

        foreach (var el in results)
        {
            Console.WriteLine("Name: " + el.Name);
            Console.WriteLine("Value: " + el.Verdi);
        }

Now the output from the program looks like what you'd expect

Sample: Leer 12
Sample ID: Leer
Name: c
Value: 0.000186156337031958
Name: co2
Value: 0.000682099902270885
Name: s
Value: 0.000121750914950204
Name: so3
Value: 0.000304028592755094

...but then after the third iteration, the NRE is thrown, pointing at the latter LINQ query. Why isn't it exiting the foreach loop like it does the first time??

Edit: Actually it's after the FOURTH iteration, sorry for the mixup! :) Thanks!

+1  A: 

The query evaluates lazily - it's only going to be performing the projection as it goes through the results. That's why you're not seeing the exception until it actually hits the problem element. To force the query to evaluate eagerly, you can call ToList.

I strongly suspect that you've got an element element which is missing either the name or value sub-element, so when you try to dereference the Value property of that sub-element, you're getting a NullReferenceException at that point.

Jon Skeet
Ah yes, I see now that there are indeed other <element> elements further down in the XML file! I only want to parse those <element> elements that are sub-elements of the <results> element, of which I have only one.
tplive
I'm not familiar with what you propose regarding forcing the query to evaluate eagerly. Can you elaborate on that?
tplive
A: 

Your excerpt is working just fine. The problem is probably somewhere else in your xml file and it most likely is that some of your elements does not have either "name" or "value" subnode.

Stanislav Kniazev
So how do I make sure that the LINQ query only parses the <element> elements within <results> and not any others?
tplive
Should I make this a new question?
tplive
A: 

Persistance prevails! I found the solution eventually! soo proud! :-)

Basically changed two lines:

XElement uniSample = XElement.Load(limsfile);
...
var results = uniSample.Element("results").Descendants("element").Select(elements => new ...

So I'm now loading up the XML in an XElement instead of an XDocument, this allowed me to more directly query the data..?

Then I added a call to get Descendants of "results" specifically, and that does the trick for making it "stop" parsing when it should.. :-)

Thanks for all your help guys!

tplive