LINQ to XML Query Extender Method for checking Nulls

Can anybody help me write a short extender method for getting attribute values in an LINQ to XML query?

I found an example that sort of does what I want to and it is only 2 lines of code but it is for elements not attributes and has some other crazy code I don't know about.  See link here > FindSiblingValues function on page:

In the code snippet below, we are checking for nulls with inline if statements.  I think these will end up getting expanded and changing overtime so it would be nice to have an extender function that is called, pass it the attribute name and have it return the value (null or otherwise).  

Then we can maintain one function for handling the nulls.  

Please take a look at my existing Query below and let me know if you have any ideas.

List<PersonsSportsInfo> personsSportsInfo =
                    (from persons in Root.Descendants("player")
                     let personsMetaData = persons.Elements("player-metadata").FirstOrDefault()
                     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 == null) ? null : (personsMetaData.Attribute("player-key") == null) ? null : personsMetaData.Attribute("player-key").Value,
                         UniformNumber = (personsMetaData == null) ? null : (personsMetaData.Attribute("uniform-number") == null) ? null : personsMetaData.Attribute("uniform-number").Value,
                         PositionRegular = (personsMetaData == null) ? null : (personsMetaData.Attribute("position-regular") == null) ? null : personsMetaData.Attribute("position-regular").Value,
                         Height = (personsMetaData == null) ? null : (personsMetaData.Attribute("height") == null) ? null : personsMetaData.Attribute("height").Value,
                         Weight = (personsMetaData == null) ? null : (personsMetaData.Attribute("weight") == null) ? null : personsMetaData.Attribute("weight").Value,
                         Status = (personsMetaData == null) ? null : (personsMetaData.Attribute("status") == null) ? null : personsMetaData.Attribute("status").Value,
                         DOB = (personsMetaData == null) ? null : (personsMetaData.Attribute("date-of-birth") == null) ? null : personsMetaData.Attribute("date-of-birth").Value,
                         Health = (personsMetaData == null) ? null : (personsMetaData.Attribute("health") == null) ? null : personsMetaData.Attribute("health").Value,
                         Caliber = (personsMetaData == null) ? null : (personsMetaData.Attribute(xts + "caliber") == null) ? null : personsMetaData.Attribute(xts + "caliber").Value,
                         FirstName = firstName,
                         LastName = lastName,
                         FullName = firstName + " " + lastName,
                         PositionDepth = (personsMetaData == null) ? null : (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.

Fernando SotoRetiredCommented:
Hi Steve;

The following is what is called an extension method much like the one I posted on your question except I like placing my extension into there own class this one is place within the same code.

The extension method must be a static method and its first parameter must be preceded by the this keyword as shown below. The extension type is of the first parameter in this case a collection of IEnumerable<XElement>.

The first line of code selects the first element that matches its name with tagName. The syntax in the ( ... ) is called a lambda expression and it states that for each element in the collection takes on the variable x, the => makes it the lambda and can be spoken as "goes to", and x.Value is matched to tagName. If one or more are fond the first is selected if none are found null is assigned.

The second line of code checks the first line of code for a value, if null returns null, otherwise it selects the first sibling's value and returns it.

public static string FindSiblingValue(this IEnumerable<XElement> elements, string tagName)
    var label = elements.FirstOrDefault(x => x.Value == tagName);
    return (label == null ? null : label.ElementsAfterSelf().First().Value);


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:
Great info as usual, thanks. Hope you are feeling better soon, thanks for taking time, it wasn't necessary.
Fernando SotoRetiredCommented:
Not a problem, always glad to help.  ;=)
kruegersteAuthor Commented:
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.