edparry
edparry

Reputation: 718

Catching non-existent XML nodes before "object not set" error

I have something similar to the XML below. I'm parsing it using Linq in C#, and it works great, until we get to a product which doesn't have a type.

<productList>
    <product>
        <type>
            <colour>red</colour>
        </type>
        <name>First</name>
    </product>
    <product>
        <name>Second</name>
    </product>
</productList>

I'm trying to access the colour element under type, but when the code reaches a product which doesn't have the type element, I get the "Object reference not set to an instance of an object" error.

Here's the code I'm using to access it at the moment. Things have got a little complicated with the attempts I've tried to solve this.

productColour = products.Element("type").Descendants().FirstOrDefault() == null ? string.Empty : products.Element("type").Descendants().FirstOrDefault().Value,

I know the colour element is always the first underneath type, so I can use .FirstOrDefault(), but I still get the same error using this code.

Can anyone point me towards the right direction? I've also tried casting to a string, and also having: ?? " " at the end, all to no avail so far.

Edit: Thanks to @anthony-pegram, it looks like the issue is that I'm always trying to grab the descendants, even if the parent element doesn't exist. So it looks like I need to check the parent element before grabbing the child - can anyone point me in a direction for this?

Upvotes: 4

Views: 1301

Answers (3)

Amicable
Amicable

Reputation: 3091

Have you thought of using an Attribute instead?

<productList>
    <product type="color-red">
        <name>First</name>
    </product>
    <product type="none">
        <name>Second</name>
    </product>
</productList>

No chance of returning a null variable, as the type attribute can have a default string value. I also think this is more tidy, but that's personal preference.

You could also do <product color="red" /> etc.

Upvotes: 0

Tallek
Tallek

Reputation: 1575

Elements() wiil return an IEnumerable. If the element does not exist, IEnumerable will just be empty and calling Elements again on it will not product a null reference exception. The code below should pull the colour from under a product\type element without throwing a null reference exception. If colour or type do not exist, it will return a null.

(string)product.Elements("type").Elements("colour").FirstOrDefault()

Upvotes: 3

L.B
L.B

Reputation: 116138

I would use XPath here

var xDoc = XDocument.Parse(xml);
var colour = xDoc.XPathSelectElement("//product/type/colour");
if(colour!=null)
{
    var val = colour.Value;
}

Upvotes: 0

Related Questions