user1644147
user1644147

Reputation: 115

Extension method for Null handling not working on linq for xml

I have an nullexception issue when trying to get the value of an xml tag, which is under a subtree that may not be there.

The extension handler works great when it can't find a tag on an existing subtree, but seems to not be able to handle when looking for a tag in a subtree that doesn't exist.

In this case, the subtree is summaryData, which may or not be there, and trying to get addressLine1 is where it doesn't handle the null, and I get the error

System.NullReferenceException occurred, Message=Object reference not set to an instance of an object.

Here is the xml, cut down for clarity, but structure is correct:

 <record>
  <accounts>
    <account >
    </account >
  </accounts>
  <summaryData>
    <Date>2013-02-04</Date>
    <address >
      <city>Little Rock</city>
      <postalCode>00000</postalCode>
      <state>AR</state>
      <addressLine1>Frank St</addressLine1>
    </serviceAddress>
  </summaryData>

</record>

My C# code is:

 xmlDoc.Descendants("account")
                //select (string)c.Element("account") ;
                select new
                {
                    //this works fine
                    Stuffinxml = c.Element("stuffinxml").Value,
                    //this field may not be there, but the handler handlers the exception correctly here when it as the correct root (account)
                    otherstuff = CustXmlHelp.GetElementValue(mR.Element("otherstuff")),
                    //this is the problem, where the summaryData root does not exist (or moved somewhere else)
                    street_address = GetElementValue(c.Element("summaryData").Element("serviceAddress").Element("addressLine1"))

                };

My extension method to handle a null is:

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

Any help would be appreciated, as I can't see why it fails when the subtree does not exist.

Upvotes: 3

Views: 298

Answers (3)

psubsee2003
psubsee2003

Reputation: 8741

As had been stated, your exception is due to the fact that you are passing multiple nested queries

c.Element("summaryData").Element("serviceAddress").Element("addressLine1")

is the equivalant of writing:

var x1 = c.Element("summaryData");
var x2 = x1.Element("serviceAddress")
var x3 = x2.Element("addressLine1")

So if any of c, x1, or x2 are null, you are going to get a NullReferenceException.

One possible alternative to a pure LINQ solution using multiple null checks, is to use XPath to build the expression.

With XPath, rather than doing a null check at every level, you can instead write your expression:

street_address = GetElementValue(c.XPathSelectElement("/summaryData/serviceAddress/addressLine1"))

This will evaluate the entire expression and if it does not exist in its entirety, it will return null, but will not thrown an exception like your pure LINQ query.

Upvotes: 1

Mathew Thompson
Mathew Thompson

Reputation: 56429

The summary data may or may not be there

That's why. As you're nesting calls, you'll have to null check them all.

Any one of these could be null:

c.Element("summaryData").Element("serviceAddress").Element("addressLine1")

Without a complex conditional, there's not a nice way around it:

street_address = c.Element("summaryData") != null
    ? c.Element("summaryData").Element("serviceAddress") != null
        ? GetElementValue(c.Element("summaryData").Element("serviceAddress").Element("addressLine1"))
        : string.Empty
    : string.Empty;

Upvotes: 2

D Stanley
D Stanley

Reputation: 152521

If the summaryDate element does not exist then

c.Element("summaryData").Element("serviceAddress").Element("addressLine1")

will throw a NullReferenceException because you're trying to call Element() on a null reference (c.Element("summaryData"))

Upvotes: 1

Related Questions