XmlObject - Adaptive Object Model

Better Designs Faster

XmlObject Derived Class

As stated earlier, the XmlObject derived classes are structured almost identically to the base classes.  Each of the classes is named after the abstract base class it is derived from but they live in a different namespace.   I should note that at one time I had envisioned there being multiple sets of classes derived from XmlObject base classes.  However with the introduction of the IXmlObjectResolver and the IXmlFragmentFactory I now think there is less to motivate such complexity.  However, it remains an option.

XmlObject Class Diagram

The derived XmlDocument class has a few additional jobs that are responsible for making the framework truly adaptive.  Early, efforts to use this framework relied on statically assembled XML documents that were then loaded and parsed.  It was cool, but not very adaptive.  To be genuinely adaptive, the framework needed a way to insert and remove objects from the object model at runtime.  The framework could do the insertion and removal easy enough, but it needed a way to create the raw XML for the framework to parse.  Since this XML is to become an object, the challenge was to do this XML generation in an application independent manner.

Thus was invented the IXmlFragmentFactory, a user implemented factory for creating fragments of XML.  Objects implementing this interface would be required to supply a single method called GetFragment.  Like the resolver, this method takes three parameters, the namespace prefix, the localName, and the namespaceURI.  This method returns a string that must represent a well formed fragment of XML.  This fragment is then parsed by the framework which creates objects as it does its work.  This fragment can represent a single object or it can represent an entire model of hierarchically related objects. 

Now the framework could accurately be called adaptive.  It is truly something to step through code and realize that the framework is loading and instantiating types from assemblies that, until a moment ago, were not even loaded into the process.  In [Yoder & Johnson 2002] Yoder talks about how novice developers are sometimes unable to understand the details of such a moment.  If you are introducing new team members to your architecture, this is a good place to spend extra time to help them understand what is going on. 

Even more so than in the base class, you will see methods here hiding the functionality.  Again this is done almost exclusively to simplify method calls and return derived types.  For example you will see that the XmlElement class implements a method called SelectSingleElement.  This method was added to hide the complexity of the NamespaceManager and to return the derived XmlElement object.  There is a similar implementation of SelectElements.

Notice also that there is a overloaded version of this method that checks for the existence of a node and throws an XmlObjectException should the element not exist.  This method was added to make it easier for developers to use asserts to ensure the existence of an object in the object model, something that is much less of a concern with a statically coded object model.

There are some other features to make note of.  The derived XmlElement class includes an event bubbling mechanism that we borrowed from HTML parsers.  As with dynamic HTML, it is difficult for the developer to know what objects are present to handle events in an adaptive object model.  The event bubbling mechanism is a simple solution to this problem.  Finally, the XmlElement has some helper methods that are used to add new fragments of XML (created by IXmlFragmentFactory) to the object model.

XmlObject Graphic