6
\$\begingroup\$

I have the following code to find xml elements that have a particular attribute value:

IEnumerable<XElement> elems = 
    xmlDoc.Descendants("elemName")
    .Where(x => 
        x.Attribute("attrName").Value
        .Equals(
            filename,
            StringComparison.OrdinalIgnoreCase
        )
    );

The problem is that if the element does not have that attribute, according to the docs, it will return null and we'll get a crash when we try to do null.Value.

I've rewritten it like this:

IEnumerable<XElement> elems = 
     xmlDoc.Descendants("elemName")
     .Where(x => 
         ((x.Attribute("attrName") == null) 
         ? "" 
         : x.Attribute("attrName").Value).Equals(
             filename,
             StringComparison.OrdinalIgnoreCase
         )
     );

But I think it's a bit ugly. Is there an idiomatic way of doing this - I imagine this is a fairly common operation? I suppose I could just do a regular loop.

\$\endgroup\$

2 Answers 2

7
\$\begingroup\$

I think you could use the null-conditional operator for x.Attribute("attrName").Value and swap arguments of String.Equals to avoid the NullReferenceException as follows:

IEnumerable<XElement> elems =
     xmlDoc.Descendants("elemName")
     .Where(x =>
         filename.Equals(
             x.Attribute("attrName")?.Value,
             StringComparison.OrdinalIgnoreCase
         )
     );
\$\endgroup\$
4
\$\begingroup\$

There is a trick - you can cast XAttribute to some data types: string, int, long, Guid, DateTime, bool etc and their nullable brothers. And if type supports null value there will be no NullReferenceException. You will simply get null as result:

(string)x.Attribute("attrName")

Next: I suggest you to use more meaningful names for variables, even if it's one-letter variable. I.e. instead of x for element you can use e.

And last, you can write following extension method to nicely compare strings

public static bool EqualsIgnoreCase(this string s, string value)
{
     return String.Equals(s, value, StringComparison.OrdinalIgnoreCase);
}

And finally your parsing query will look like

from e in xmlDoc.Descendants("elemName")
where filename.EqualsIgnoreCase((string)e.Attribute("attrName"))
select e;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.