I often work with dynamic XML documents which might or might not contain the element, field or attribute that I am looking for. The Standard .NET XElement class is pretty strict (as it should be) and returns a null reference execption if you ask for the value of an element that is not there:
<employees> <employee id="bp"> <name>Brian</name> </employee> <employee id="ap"> <name>Anita</name> <position>CEO</position> </employee> </employees>
In the example above I can look for the position element for employee AP, but not for employee BP. Instead of building my exception handling every time I ask for the position element, I have built a set of extension methods that take care of this.
Extension methods 1 and 2: SafeValue and SafeAttribute
The following methods allows me to return a default value if the value of either an element or an attribute is not present:
using System.IO; using System.Text; using System.Xml; using System.Xml.Linq; namespace MyCode.Extensions { public static class XElementExtension { public static string SafeValue(this XElement element, string defaultValue) { if (element == null) return defaultValue; if (element.Value == null) return defaultValue; return element.Value; } public static string SafeAttribute(this XElement element, XName name, string defaultValue) { if (element == null) return defaultValue; if (element.Attribute(name) == null) return defaultValue; if (element.Attribute(name).Value == null) return defaultValue; return element.Attribute(name).Value; } } }
Extensions 3 and 4: GetElementFromPath and GetValueFrompath
These extensions are more exotic. They allow me to ask for an element or a value down a path from the current element, returning a default value if the element or value is not present:
public static XElement GetElementFromPath(this XElement element, params string[] path) { if (element == null) return null; XElement current = element; foreach (string s in path) { if (current != null && current.Element(s) != null) current = current.Element(s); } return current; } public static string GetValueFromPath(this XElement element, params string[] path) { if (element == null) return string.Empty; XElement current = element; foreach (string s in path) { if (current != null && current.Element(s) != null) current = current.Element(s); } return current != null ? current.Value : ""; }
The functions might seem strange, but it’s cool to be able to do this:
element.GetValueFromPath("employee", "position");
Extension 5: Convert XElement to XmlElement
The last extension method is a old goodie. Converting from the LINQ based XElement to the old-fashioned XmlElement class is handy when working with web services or other methods that requires the old XmlElement.
public static XmlElement ToXmlElement(this XElement element) { return new XmlService(element).CreateXmlElement(); } #region internal conversion class internal class XmlService { private readonly StringBuilder _sb; private readonly XmlWriter _writer; private XmlService() { _sb = new StringBuilder(); _writer = new XmlTextWriter(new StringWriter(_sb)) { Formatting = Formatting.Indented, Indentation = 2 }; } public XmlService(XNode e) : this() { e.WriteTo(_writer); } public XmlService(XmlNode e) : this() { e.WriteTo(_writer); } public XElement CreateXElement() { return XElement.Load(new StringReader(_sb.ToString())); } public XDocument CreateXDocument() { return XDocument.Load(new StringReader(_sb.ToString())); } public XmlElement CreateXmlElement() { return CreateXmlDocument().DocumentElement; } public XmlDocument CreateXmlDocument() { var doc = new XmlDocument(); doc.Load(new XmlTextReader(new StringReader(_sb.ToString()))); return doc; } } #endregion
