Wriju's BLOG

.NET, Cloud and everything

LINQ to XML : Handling blank or no Element and Attribute

It quite so happen that you are working with XML where you are expecting a specific element in every set. But somehow that is missing in some of the sets.

Now at runtime you would get an error..

The XML file which I am targeting

<?xml version="1.0" encoding="utf-8"?>
<Employees>
  <Employee Location="Earth">
    <Name>Wriju</Name>
    <Email>a@a.com</Email>
  </Employee>
  <Employee Location="Moon">
    <Name>Tupur</Name>
    <Email>a@b.com</Email>
  </Employee>
  <Employee>
    <Name>Wrishika</Name>
  </Employee>  
</Employees>

Notice above the third element has missing Location attribute and Email element. So this would throw me a runtime error if I try to execute as below.

var xml = XElement.Load(@"D:\Temp\Employee.xml");

var q = from e in xml.Descendants("Employee")
        select new 
        {
            Name = e.Element("Name").Value,
            Location = e.Attribute("Location").Value,
            Email = e.Element("Email").Value
        };

foreach (var k in q)
{
    Console.WriteLine("Name : {0}, Email : {1}, Location : {2}", 
        k.Name, k.Email, k.Location);
}

Error would come for the 3rd element where both Location attribute and Email element are missing.

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object

Now what I need is simple. By using C# 3.0 extension method I can create two additional methods in a public static class as below

//This method is to handle if element is missing
public static string ElementValueNull(this XElement element)
{
    if (element != null)
        return element.Value;

    return "";
}

//This method is to handle if attribute is missing
public static string AttributeValueNull(this XElement element, string attributeName)
{
    if (element == null)
        return "";
    else
    {
        XAttribute attr = element.Attribute(attributeName);
        return attr == null ? "" : attr.Value;
    }
}

Now my code would look like and would not throw any runtime error

var xml = XElement.Load(@"D:\Temp\Employee.xml");

var q = from e in xml.Descendants("Employee")
        select new 
        {
            Name = e.Element("Name").ElementValueNull(),
            Location = e.AttributeValueNull("Location"),
            Email = e.Element("Email").ElementValueNull()
        };

foreach (var k in q)
{
    Console.WriteLine("Name : {0}, Email : {1}, Location : {2}", 
        k.Name, k.Email, k.Location);
}

Namoskar!!!