Handling Attribute Nulls in LINQ to XML Query

What is the best way to handle null Attributes when assigning the value in an LINQ query?

See the code snippet below, many examples.  We are currently using inline if statements to check if the attribute exists and then handle if it does or not. For example:

 Height = (personsMetaData.Attribute("height") == null) ? null : personsMetaData.Attribute("height").Value,

If this is the best way, anybody have any examples of an extender function  that would cut down on the amount of code for checking nulls inside the query?  Something that could be a little easier maintained?

List<PersonsSportsInfo> personsSportsInfo =
                    (from persons in Root.Descendants("player")
                     let personsMetaData = persons.Elements("player-metadata").First()
                     let firstName = (personsMetaData.Element("name") == null) ? "" : (personsMetaData.Element("name").Attribute("first") == null) ? "" : personsMetaData.Element("name").Attribute("first").Value
                     let lastName = (personsMetaData.Element("name") == null) ? "" : (personsMetaData.Element("name").Attribute("last") == null) ? "" : personsMetaData.Element("name").Attribute("last").Value
                     let careerPhase = persons.Descendants("career-phase")
                     select new PersonsSportsInfo
                         Key = (personsMetaData.Attribute("player-key") == null) ? null : personsMetaData.Attribute("player-key").Value,
                         UniformNumber = (personsMetaData.Attribute("uniform-number") == null) ? null : personsMetaData.Attribute("uniform-number").Value,
                         PositionRegular = (personsMetaData.Attribute("position-regular") == null) ? null : personsMetaData.Attribute("position-regular").Value,
                         Height = (personsMetaData.Attribute("height") == null) ? null : personsMetaData.Attribute("height").Value,
                         Weight = (personsMetaData.Attribute("weight") == null) ? null : personsMetaData.Attribute("weight").Value,
                         Status = (personsMetaData.Attribute("status") == null) ? null : personsMetaData.Attribute("status").Value,
                         DOB = (personsMetaData.Attribute("date-of-birth") == null) ? null : personsMetaData.Attribute("date-of-birth").Value,
                         Health = (personsMetaData.Attribute("health") == null) ? null : personsMetaData.Attribute("health").Value,
                         Caliber = (personsMetaData.Attribute(xts + "caliber") == null) ? null : personsMetaData.Attribute(xts + "caliber").Value,
                         FirstName = firstName,
                         LastName = lastName,
                         FullName = firstName + " " + lastName,
                         PositionDepth = (personsMetaData.Element("player-metadata-american-football") == null) ? null : (personsMetaData.Element("player-metadata-american-football").Attribute(xts + "position-depth") == null) ? "" : personsMetaData.Element("player-metadata-american-football").Attribute(xts + "position-depth").Value,
                         ProExperience = careerPhase
                             .Where(c => c.Attribute("phase-type").Value == "professional")
                             .Select(c => c.Attribute("duration").Value).FirstOrDefault(),
                         CollegeName = careerPhase
                             .Where(c => c.Attribute("phase-type").Value == "college")
                             .Select(c => c.Attribute("name").Value).FirstOrDefault(),

Open in new window

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Jens FiedererTest Developer/ValidatorCommented:
You could certainly make the code more palatable by defining a function

object GetValue(DataTypeOfAttributeEntry foo) {
      return (foo == null) ? null : foo.Value;

and using
 Key = GetValue(personsMetaData.Attribute("player-key"));

etc., instead.

(if you these values are always strings, it could be string GetValue)

Fernando SotoRetiredCommented:
Hi Steve;

Sorry but I have been sick as a dog for the last three days and have not even come near a computer to help out here and I am still a little sick.

In answer to your  questions the way you are doing it would be the best way. You could use extension methods to make it a little more readable. To do this add the class in the code snippet to your project read the comments for needed changes. then your line of code:

Height = (personsMetaData.Attribute("height") == null) ? null : personsMetaData.Attribute("height").Value,

would become:

Height = personsMetaData.Attributes().AttributeExist("height") ? personsMetaData.Attribute("height").Value :null,

The following is what is happening:
1. personsMetaData is a single element of type "player-metadata"
2. Attributes returns a collection of all its attributes
3. AttributeExist is the extension method which return true/false if its parameter exist
4. Height gets assign the value of the attribute if true otherwise null.

The length of the line is a little but longer but I think would be a little more readable.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

// use the same namespace as your project or create a new namespace then add a using statement where you will use it
namespace WindowsFormsApplication11
    // Create a public static class
    public static class Elements
        // Create the extension method that will be called from the Linq query. Give it a meaningful name in this cans
        // AttributeExist of generic type T also in this case returning a bool but can be of any type. The "this" keyword
        // in the first parameter makes it a extension method. The where at the end restricts it to type of XAttributes
        public static bool AttributeExist<T>(
            this System.Collections.Generic.IEnumerable<T> source, string attributeName) where T : System.Xml.Linq.XAttribute
            // Set up the return value
            bool nameFound = false;
            // Check the attribute names for a match
            foreach (XAttribute a in source as IEnumerable<T>)
                if (a.Name == attributeName)
                    // Attribute name was found set value and exit foreach
                    nameFound = true;
            return nameFound;

Open in new window


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
kruegersteAuthor Commented:
Awesome example, thanks looks great.  Hope you are feeling better soon, thanks for taking time, it wasn't necessary.
Fernando SotoRetiredCommented:
Not a problem, glad to help out.  ;=)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.