Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't XmlDocument dynamic in .NET 4?

One of the areas where I would like to see the use of dynamic is XML. I think it would make XML processing code simpler to write and I believe I saw some examples on that before C# 4 came out and it's mentioned in this answer as one of the uses of this feature.

So, my question is this: why wasn't the XmlDocument (or XDocument) made dynamic, or why isn't there some new class for dynamic XML manipulation in C# 4?

This is even more strange to me, when I consider that in PowerShell, XmlDocument is dynamic, code like $xmlDoc.root.subnode.subsubnode works there.

like image 536
svick Avatar asked Jun 23 '10 01:06

svick


2 Answers

I'm surprised at the amount of seemingly authoritative discussion without an answer. Your question is FANTASTIC. It addresses EXACTLY the kind of awesome things the dynamic keyword was intended for. The trouble is, not a lot of people really know how to use it to its fullest.

While MS didn't build the dynamic XML objects for us, they did give us the tools to do it ourselves with the DynamicObject class. Here's one way to do what you're asking for with the old XmlDocument class.

public class DynamicXmlElement : DynamicObject {
   XmlElement _xmlEl;

   public DynamicXmlElement(string xml) {
      var xmldoc = new XmlDocument();
      xmldoc.LoadXml(xml);
      _xmlEl = xmldoc.DocumentElement;
   }

   public DynamicXmlElement(XmlElement el) {
      _xmlEl = el;
   }

   public override bool TrySetMember(SetMemberBinder binder, object value) {
      return false;
   }

   public override bool TryGetMember(GetMemberBinder binder, out object result) {
      XmlElement el = (XmlElement)_xmlEl.SelectSingleNode(binder.Name);
      if (el != null) {
         // wrap the element we found in a new DynamicXmlElement object
         result = new DynamicXmlElement(el);
         return true;
      }
      else if (binder.Name == "root") {
         // special case for handling references to "root"
         result = new DynamicXmlElement(_xmlEl.OwnerDocument.DocumentElement);
         return true;
      }
      else {
         // feel free to change this to prevent having accidental null reference issues
         // by just setting the result to a DynamicXmlElement with a null element and 
         // handling _xmlEl == null at the start of this method
         result = null;
         return false;
      }
   }

   public override string ToString() {
      return _xmlEl.InnerText;
   }
}

And here's how you would call the code. Note that this compiles in C# 4.0 only.

namespace ConsoleApplication4 {
   class Program {
      static void Main(string[] args) {
         var xmlstr = "<r><subnode><subsubnode>ABCs of dynamic classes</subsubnode></subnode></r>";
         dynamic xml = new DynamicXmlElement(xmlstr);
         Console.WriteLine(xml.subnode.root.subnode.subsubnode); // take the long way around...
         Console.ReadKey(true);
      }
   }
}

I can't take all the credit for this. Bamboo wrote this code for Boo back in 2003. C# has slowly been getting the features that Boo has had in .NET for years... first type inference, and now the IQuackFu style DynamicObject. Once they implement language macros so that you can make DSLs, I think they'll have caught up.

I'll leave writing the newer style XElement version of this code to the reader.

like image 163
mattmc3 Avatar answered Sep 30 '22 05:09

mattmc3


Given some of the comments, let me provide an alternative answer. The original question asked why XmlDocument was not dynamic in .NET 4. While it may be possible to add "expando" property capability to the existing xml document classes via IDynamicMetaObjectProvider, doing so is likely a non-trivial endeavor. Making the original Xml object model from System.Xml fully dynamic would require some extensive modification of the Xml framework, and would require that IDynamicMetaObjectProvider be added to every object that is involved. That includes XmlDocument, XmlElement, XmlAttribute, XmlNode, and all of the other xml content types like comments, text nodes, etc. In addition, a considerable amount of support infrastructure, internal types, etc. that are involved in the lookup and processing of elements and attributes and values would also need to be modified (open up Reflector, and take a look at System.Xml...more than half of the types are internal, and they are all highly interdependent with each other and the available public types.)

It is also important to consider the proper scope of implementing expando properties for Xml in .NET. Would you stop at just the XmlDocument and related types? Or would it be more appropriate to include XPath, Xml Schema, etc.?

To answer the original question, "Why isn’t XmlDocument dynamic in .NET 4?", I think the simple answer is this: Implementing fully 'dynamic' API's, or in the case of Xml here, API's that provide property expansion of arbitrary xml documents, is far from a trivial task. Given Microsoft's work ethic, it makes logical sense that they would not approach such a task lightly, and if they attempt to implement expando properties for the Xml framework, I would hope and expect it to be done with the same level of careful attention and care they give to the rest of .NET.

like image 38
jrista Avatar answered Sep 30 '22 04:09

jrista