When we (my team at AIS) some xml parsing for the Rolling Stone project, we had to convert element and attribute values to ints and dates, etc. We ran into the problem that sometimes these elements and attributes didn’t exist – so using myXElement.Attribute(myAttribute).Value in a TryParse() would fail with a NullReferenceException, since Value couldn’t be called on a non-existent attribute.
Classic case for an Extension method – which is what I created:
public static T GetAttributeValueOrDefault(this XElement element, XName attributeName, T defaultValue) where T : struct
{
//First check that the attribute is present
XAttribute attribute = element.Attribute(attributeName);
if (attribute == null || attribute.Value == null || attribute.Value == "null")
{
return defaultValue;
}
//...else attempt conversion
return attribute.Value.ConvertOrDefault(defaultValue);
}
…except that we were all WRONG: http://www.hanselman.com/blog/ImprovingLINQCodeSmellWithExplicitAndImplicitConversionOperators.aspx
It turns out XAttribute has a series of explicit conversion operators, as does XElement:
Reflector reveals the following for XAttribute (XElement also has the same operators)
public class XAttribute : XObject
{
…
// Methods
…
[CLSCompliant(false)]
public static explicit operator DateTime?(XAttribute attribute);
[CLSCompliant(false)]
public static explicit operator bool(XAttribute attribute);
[CLSCompliant(false)]
public static explicit operator Guid(XAttribute attribute);
[CLSCompliant(false)]
public static explicit operator bool?(XAttribute attribute);
[CLSCompliant(false)]
public static explicit operator int(XAttribute attribute);
[CLSCompliant(false)]
public static explicit operator Guid?(XAttribute attribute);
[CLSCompliant(false)]
public static explicit operator int?(XAttribute attribute);
…
//etc, etc, etc – umpteen more
…
The implementation of the int? version looks like this;
[CLSCompliant(false)]
public static explicit operator int?(XAttribute attribute)
{
if (attribute == null)
{
return null;
}
return new int?(XmlConvert.ToInt32(attribute.value));
}
So to get the value of an XElement/XAttribute, simply cast it to the type you want – make it the nullable variety if you aren’t sure that the attribute/element is present, the explicit conversion operator will check and convert the value for you, then check for null in your code…
Live and learn.
PS! How are you expected to discover this, without reading the source-code (or Scott’s blog)?
Labels: howto, linq, microsoft, xml