XElement get default values using extension methods

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

About briancaos

Developer at Pentia A/S since 2003. Have developed Web Applications using Sitecore Since Sitecore 4.1.
This entry was posted in .net, c#, General .NET and tagged , , , , . Bookmark the permalink.

One Response to XElement get default values using extension methods

  1. Dawn says:

    // 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;
    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s