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
// For extensions 1 and 2, there is a simple way to do.
XElement x = new XElement(“Node”, new XText(“123”));
XElement y = new XElement(“Node”);
XElement z;
string xValue = (string)x; // “123”
string yValue = (string)y; // “”
string zValue = (string)z; // null
// If you need a empty string as default
string xValue = (string)x ?? “”; // “123”
string yValue = (string)y ?? “”; // “”
string zValue = (string)z ?? “”; // “”
// Get the XAttribute Value in the same way.
// For extensions 3 and 4, .Net Framework 4.0 supports XPath.
// For extensions 5, I didn’t convert the XElement to XmlElemtn, but XDocument to XmlDocument, and also used the extenstion method.
public static XmlDocument CreateXmlDocument(this XDocument xDoc)
{
XmlReader reader = xDoc.CreateReader();
reader.MoveToContent();
XmlDocument doc = new XmlDocument();
XmlNode cd = doc.ReadNode(reader);
doc.AppendChild(cd);
return doc;
}
LikeLike