views:

243

answers:

4

This may be a simple fix (well, it probably is) but for some reason I just can't figure it out.

So, I have some xml that looks something like this:

XElement xml = XElement.Parse (
@"<Alphabet>
     <a name="A" />
     <b name="B" />
     <d name="D" />
     <e name="E" />
</Alphabet>");

So later in my code, I reference a node that may or may not exist in there like so:

var name = (from b in xml.Descendants("c")
            select b.Attribute("name")).FirstOrDefault().Value;

But when it doesn't exist, instead of returning null or "" it throws a NullReferenceException: Object reference not set to an instance of an object.

What's the best way to check and see if a node actually exists in my linq query? Or do I need to check if it exists some other way?

+1  A: 

Well, you're selecting the attribute - so just use:

var nameAttribute = xml.Descendants("c").Select(b => b.Attribute("name"))
                                        .FirstOrDefault();
if (nameAttribute != null)
{
    string name = nameAttribute.Value;
}
else
{
    // Whatever...
}

(I've changed it from a query expression to dot notation because the query was trivial - query expression syntax wasn't actually buying you anything.)

One problem with this solution: it doesn't differentiate between there being a "c" element but it not having a "name" attribute, and there not being a "c" element in the first place. Do you need to be able to tell the difference?

Jon Skeet
Thanks for the answer - No, I don't need to able to tell the difference so this will work great. I'm interested in you saying "query expression syntax wasn't actually buying you anything" - I always assumed that choosing one syntax over the other was based on preference - is there actually a performance reason to dot notation over query expression? Or maybe that's a whole different subject. Google here I come!
onekidney
@Skeet - Ayende said something about that for Linq as well. Care to elaborate why it's beneficial?
mhenrixon
No performance reason at all - just that the "from x in y" is just extra fluff in this case. See http://msmvps.com/blogs/jon_skeet/archive/2009/01/07/you-don-t-have-to-use-query-expressions-to-use-linq.aspx
Jon Skeet
+2  A: 

I created extension methods to do that for me.

public static string GetAttributeValue(this XElement element, string attributeName)
{
    XAttribute attribute = element.Attribute(attributeName);
    return attribute != null ? attribute.Value : string.Empty;
}

public static string GetElementValue(this XElement element)
{
    return element != null ? element.Value : string.Empty;
}

public static string GetElementValue(this XElement element, string elementName)
{
    XElement child = element.Element(elementName);
    return child != null ? child.Value : string.Empty;
}
mhenrixon
Hey, nice. I'm gonna use those. Why didn't I think of that.
Patrick Karcher
Feel free to use them :)
mhenrixon
A: 

You can do something like this:

var name = (from b in xml.Descendants("c")
            select b.Attribute("name").Value).FirstOrDefault();

or if you really need the element:

var name = (from b in xml.Descendants("c")
            select b.Attribute("name")).FirstOrDefault();

if (name != null)
{
    // your logic ...
}
bruno conde
+1  A: 

FirstOrDefault returns null or an XAttribute which you can cast to a string to get the value:

var name = (string)((from b in xml.Descendants("c")
                     select b.Attribute("name")).FirstOrDefault());

or

var name = (string)xml.Descendants("c")
                      .Select(b => b.Attribute("name"))
                      .FirstOrDefault();
dtb