views:

1374

answers:

2
<?xml version="1.0" encoding="utf-8" ?>
<pages> 
  <page id="56">
    <img id="teaser" src="img/teaser_company.png"></img>
  </page>  
</pages>

I have an xml file that defines additional resources for pages within a cms. What's the best way to guard for Null Reference exceptions when querying this file with LinqToXml?

var page = (from tabElement in extensionsDoc.Descendants("page")
where tabElement.Attribute("id").Value == tabId.ToString()
select tabElement).SingleOrDefault();

This code could potentially trigger a Null Reference exception if a page element doesn't have an attribute called "id". Do I have to use a try catch block or is there a way to handle this? For instance return null for page the page object if there's no attribute called "id" for the page element.

+8  A: 

The simplest way would be something like:

var page = (from tabElement in extensionsDoc.Descendants("page")
            let idAttribute = tabElement.Attribute("id")
            where idAttribute != null 
                  && idAttribute.Value == tabId.ToString()
            select tabElement).SingleOrDefault();

Alternatively you could write an extension method to XElement:

public static string AttributeValueOrDefault(this XElement element,
                                             string attributeName)
{
    XAttribute attr = element.Attribute(attributeName);
    return attr == null ? null : attr.Value;
}

then use:

var page = (from element in extensionsDoc.Descendants("page")
            where element.AttributeValueOrDefault("id") == tabId.ToString()
            select element).SingleOrDefault();

Or to use dot notation:

var page = extensionsDoc.Descendants("page")
             .Where(x => x.AttributeValueOrDefault("id") == tabId.ToString())
             .SingleOrDefault();

(It would make sense to call tabId.ToString() once beforehand, btw, rather than for every iteration.)

Jon Skeet
thanks a lot Jon
kitsune
Btw, there's an error in your AttributeValueOrDefault extension method
kitsune
Fixed - but in future it would be helpful to say what the error is, instead of just that there is one :)
Jon Skeet
Sorry :) You're right of course
kitsune
No problem. Does it now work for you?
Jon Skeet
yes thank you very much
kitsune
+1  A: 

I've seen other people use a straight cast to a string before as well; I don't know if it's any more or less efficient than what Jon suggested, but I quite like the syntax.

var page = extensionsDoc.Descendants("page")
             .Where(x => (string)x.Attribute("id") == tabId.ToString())
             .SingleOrDefault();

Anyone feel free to fix that if there's some flaw in my thinking; I'm quite new to LINQ.

Gavin Schultz-Ohkubo