This particular series has been ongoing since late last year - not quite a book, though a very healthy chapter towards one, fortunately. When I started it, I was hoping to learn a little bit myself about XForms, as teaching a new technology is, at least for me, one of the best ways I can think of to learn one. However, along the way, I have learned quite a bit, both good and bad, about this technology, and have to admit that I see far more potential in it now than I did when first I addressed the issue in Revisiting XForms.

XForms is not perfect - there were times when I was working on things that I found XForms to be very limiting indeed, sometimes over the most trivial issues. Working on an in-progress implementation certainly didn’t help with this, of course, though I will readily admit that, even unfinished, the Mozilla Firefox XForms implementation is very, very effective, something I’ll say more about at the end of this article.

XBL Redux

I’ve already dealt with XBL previously in this series, but at the time specifically avoided getting into the use of such bindings much beyond creating simple replacements for certain elements (such as displaying images rather than URIs in output elements). However, as part of the advantage of the Mozilla XForms implementation comes in its integration with XBL, I felt it was worthwhile to readdress the XForms/XBL connection in a little more depth.

The first facet about XForms that I wanted to explore is its dirty little secret - a small amount of the XForms implementation exists as a set of binary services, largely for performance sake. However, probably 95% of the actual XForms implementation is written in … XBL. In other words, at least on the Mozilla platform, what you are in fact doing when you create an extension to a given XForms element is simply subclassing the existing XBL implementation. Once you understand this, you can do an incredible amount of magic without ever having to bother with powering up a compiler.

This implementation exposes a number of system defined interfaces that you can access through JavaScript. For most components, the base object that’s exposed is the nsIXFormsUIWidget object, which provides a number of virtual methods and properties that can be subclassed. This interface is, for the most part expressed as part of a specialized object called the accessors object (nsIXFormsAccessors), which has the following properties:

Table 1. Accessors Object Interface
getValue() This returns the rectified value of the binding for the given object, in its pre-defined schema type.
QueryInterface() This provides the interfaces necessary to do discovery on the object. Seldom used from JavaScript.
setValue(val) This sets the value of the data element bound to the component.
isReadonly() This (read-only) property determines whether the object in question can be written to or not.
isRelevant() This (read-only) property determines whether the object is relevant (has a bound node with relevant = "true|false").
isRequired() This (read-only) property determines whether the object is required (has a bound node with required = "true|false").
isValid() This (read-only) property determines whether the object is valid based upon the constraints set upon it
hasBoundNode() This returns true if the object currently has a bound node in the data model that it is associated with. This is false if the node was calculated from multiple bindings.
getBoundNode() This returns the bound node from the data model that’s associated with the component, if such a binding exists.
setContent(containerNode,forceUpdate) In certain cases the content of a given element in the data model consists of more than just a text string, but may be an entire set of nodes. In that particular case, you would use setContent method to take the contents of a given container node, copy them, and place the results into the model. If forceUpdate is true, this will automatically update the model and force a refresh of the XFOrms elements on the page.

The accessors object provides a low level interface that is inherited by all XForms UI Widgets, although each individual element may also extend this with additional properties on the object itself. For most of the core input and output type elements, the interfaces share a great deal in common, with most of these interface methods described as follows:

Table 2. Common Element Interfaces
_control Internal variable for control, which should be used instead.
_delegate Internal variable for delegate, which should be used instead.
_accessors Internal variable for accessors, which should be used instead.
widgetAttached Method used by the internal delegate handlers for the components. Should generally not be used from JavaScript.
getXFormsAccessors This retrieves the accessors object.
reportError This returns the error object populated when an error occurs
getControlElement() This returns the underlying XHTML object that generates the primary control, such as a span for an output or an input text box for an input control.
refresh() This method is invoked whenever the underlying XForms model is refreshed, and can be overridden to provide custom update to the component in question.
focus() This method is invoked whenever the control receives the focus, and can be overridden in order to update the component upon receiving the onfocus() event.
updateInstanceData This invokes a rebuild() and recalculate on the underlying data model’s instance associated with the bound object.
disable(disableState) This disables the control, and sets the requisite hooks so that any CSS disable rendering is provided. The object will not update itself until this is restored.
accessors This is an object containing the various accessors methods.
stringValue This is a read-write property for either reading or setting the value of the component, given as a string.
delegate This is an internal representation of the object itself.
XFORMS_NS This is the XForms Namespace - “http://www.w3.org/2002/xforms”
dispatchDOMUIEvent(eventname) This is used to notify the XForms system that the DOM UI has been refreshed.
dispatchXFormsNotificationEvent(eventname) This is used to notify the XForms system that the model has been modified.
control control description

The control object is fairly important within the general API - it is essentially the XHTML component that either receives or displays the information bound from the model, and as such exists as a somewhat privileged entity. When you set the .xf-value class in CSS, what you are actually doing is setting the styling for this particular control. Since subclassing an XForms object usually entails modifying or replacing this particular control, knowing what the control is in the first place is crucial.

An example at this stage could prove useful to understanding in a little more detail what exactly is going on with these commands. The output element is one of the more intriguing in the XForms panoply, in great part because it is so easy to subclass and its uses are fairly obvious. For instance, suppose that a particular element in the model (call it description) contained XHTML comment to display. This would be very difficult for “stock” XForms to handle, but its not hard to imagine an output element of the form:

<xf:output ref="description" appearance="xhtml"/>

Fortunately, with XBL, you can create a binding on any attribute using a CSS statement that points to the binding:

@namespace xf url('http://www.w3.org/2002/xforms');
xf|output[appearance='xhtml'] {
       url('xformsExtensions.xml#output-xhtml');

This is displayed in the Listing 1, xformsXBL1.xhtml:

<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:ev="http://www.w3.org/2001/xml-events">
    <head>
        <title/>
        <xf:model>
            <xf:instance>
<data xmlns="">
    <description xmlns:h="http://www.w3.org/1999/xhtml">
        <h:div>
            <h:h3>Message</h:h3>
            <h:p>This is a message describing meaningful, signficant and important
                content ... really!</h:p>
            <h:p>
                <h:i>Along with a completely unimportant and irrelevant
                    message.</h:i>
            </h:p>
        </h:div>
    </description>
    <description xmlns:h="http://www.w3.org/1999/xhtml">
        <h:div>
            <h:h3>A second message</h:h3>
            <h:p>Here's an even more basic message that the previous one, perhaps
                not quite as insightful, but nonetheless still relevant.</h:p>
            <h:p>
                <h:i>Along with another completely unimportant and irrelevant
                    message.</h:i>
            </h:p>
        </h:div>
    </description>
    <description xmlns:h="http://www.w3.org/1999/xhtml">
        <h:div xmlns="http://www.w3.org/1999/xhtml">
            <h:h3>The final message</h:h3>
            <h:p>This is the end-all and be-all (or at least end-all) of the
                messages. This is it, there ain't no more.</h:p>
            <h:p>
                <h:i>Except this message, of course.</h:i>
            </h:p>
        </h:div>
    </description>
</data>
            </xf:instance>
        </xf:model>
        <style type="text/css">
@namespace xf url('http://www.w3.org/2002/xforms');
xf|output[appearance='xhtml'] {-moz-binding:url('xformsExtensions.xml#output-xhtml');}            
</style>
    </head>
    <body>
        <xf:trigger>
            <xf:label>Message 1</xf:label>
            <xf:toggle case="btn1" ev:event="DOMActivate"/>
        </xf:trigger>
        <xf:trigger>
            <xf:label>Message 2</xf:label>
            <xf:toggle case="btn2" ev:event="DOMActivate"/>
        </xf:trigger>
        <xf:trigger>
            <xf:label>Message 3</xf:label>
            <xf:toggle case="btn3" ev:event="DOMActivate"/>
        </xf:trigger>
        <xf:switch>
            <xf:case id="btn1">
                <xf:output ref="description[1]" appearance="xhtml"/>
            </xf:case>
            <xf:case id="btn2">
                <xf:output ref="description[2]" appearance="xhtml"/>
            </xf:case>
            <xf:case id="btn3">
                <xf:output ref="description[3]" appearance="xhtml"/>
            </xf:case>
        </xf:switch>
    </body>
</html>
            
xformsXBL1.png

It’s worth noting such things as the use of the XHTML namespace for the content within the <description> blocks.. This code creates a switch view (akin to a set of three tapped pages) with each page holding a single XHTML block of content. Clicking on the buttons above the content bring up the appropriate page. Also, while this has the content inline, a more realistic application would likely have this data referenced via the <xf:instance>’s src attribute.

The specific binding file itself is pretty typical for such XForms bindings, and is shown on Listing 2, XFormsExtensions.xml:

<xbl:bindings xmlns:xbl="http://www.mozilla.org/xbl" 
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms">
    <xbl:binding id="output-xhtml" 
          extends="chrome://xforms/content/xforms.xml#xformswidget-base">
        <xbl:content>
            <span style="display:none;">
                <xbl:children/>                
            </span>
            <div anonid="content">
            </div>            
        </xbl:content>
        <xbl:implementation implements="nsIXFormsUIWidget">
            <xbl:method name="refresh">
                <xbl:body><![CDATA[
    var content = document.getAnonymousElementByAttribute(this,"anonid","content");
    while (content.firstChild != null){
        content.removeChild(content.firstChild);
        }
    var boundNode = this.accessors.getBoundNode();
    for (var index=0; index != boundNode.childNodes.length;index++){
        var newNode = boundNode.childNodes.item(index).cloneNode(true);
        content.appendChild(newNode);
        }
    return true;
]]></xbl:body>
            </xbl:method>
        </xbl:implementation>
    </xbl:binding>
</xbl:bindings>                
            

The first point to note within the binding is that the screen is redrawn via the refresh() method, which is automatically invoked by the XForms engine whenever the control needs to be redrawn (including the first time it’s rendered). For this reason, unless you are initializing state variables within the binding, it is far more likely that the code you write will likely end up in refresh() rather than putting such code in the constructor block.

The getBoundNode() method is the key to doing most of the work here. The bound node is the node that the <xf:input> or <xf:output> watches (or modifies) via the ref node, though if the component uses a bind attribute instead, then getBoundNode() will return the node referenced by the binding. Finally, if any XForms component that supports it uses the value attribute, then the bound node is the one that’s implicitly referenced by the current context.

The <xbl:content> node exists to do a couple of things. First, it overrides the existing control, so that the output isn’t directed into the existing objects. Additionally, all of the children of the control (labels and so forth) are also redirected into a hidden <div> element - they are still accessible, but they aren’t explicitly displayed. You can retrieve the children by using the getElementsByTagNameNS() function. For instance, the following retrieves the <xf:label> node, if it exists, for the control:

var label = this.getElementsByTagNameNS(this.XFORMS_NS,"label")[0];

Finally, once the bound node is retrieved, the component should empty out the existing content within the display portion of the control, a process that is accomplished by removing the first element of the control’s children until there are no such elements left:

                while (content.firstChild != null){
                content.removeChild(content.firstChild);
                }                
            

If this step is left out, then the new content will appear after the existing content, rather than replacing it. While generally this isn’t desireable, it can come in handy if you are wishing to create a log or similar archive of your actions (you’d use insertBefore() rather than append() of course to put the most recent items of the log on top, rather than on the bottom.

Note that you can similarly pull in external resources using XMLHttpRequest from within a binding. In this case, the bound object is a URL that can be loaded in and displayed in a similar manner to the above. Additionally, sub-document references (via hash marks (#) in the URL) make it possible to retrieve subordinate content from an external document - something that can be accomplished easily enough with JavaScript.

The one change in approach here comes in the use of a slightly different attribute - mediatype, rather than appearance, within the input or output element. The mediatype attribute is part of the XForms 1.1 specification, which will likely be supported by Mozilla Firefox in the near future but which currently is outside the scope of development, and is intended to provide some indicator to how the referenced resource will be displayed. Listing 3, xformxXBL2.xhtml, shows how this slightly changed attribute would be declared:

<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:ev="http://www.w3.org/2001/xml-events">
    <head>
        <title/>
        <xf:model>
            <xf:instance>
                <data xmlns="">
                    <description>messages.xhtml#msg1</description>
                    <description>messages.xhtml#msg2</description>
                    <description>messages.xhtml#msg3</description>
                </data>
            </xf:instance>
        </xf:model>
        <style type="text/css"><![CDATA[
@namespace xf url('http://www.w3.org/2002/xforms');
xf|output[mediatype='xhtml'] {
       -moz-binding:url('xformsExtensions.xml#output-type-xhtml');}            
]]></style>
    </head>
    <body>
        <xf:trigger>
            <xf:label>Message 1</xf:label>
            <xf:toggle case="btn1" ev:event="DOMActivate"/>
        </xf:trigger>
        <xf:trigger>
            <xf:label>Message 2</xf:label>
            <xf:toggle case="btn2" ev:event="DOMActivate"/>
        </xf:trigger>
        <xf:trigger>
            <xf:label>Message 3</xf:label>
            <xf:toggle case="btn3" ev:event="DOMActivate"/>
        </xf:trigger>
        <xf:switch>
            <xf:case id="btn1">
                <xf:output ref="description[1]" mediatype="xhtml"/>
            </xf:case>
            <xf:case id="btn2">
                <xf:output ref="description[2]" mediatype="xhtml"/>
            </xf:case>
            <xf:case id="btn3">
                <xf:output ref="description[3]" mediatype="xhtml"/>
            </xf:case>
        </xf:switch>
    </body>
</html>                
            

This assumes that the messages in the previous example were consolidated into a single XHTML document and assigned reference ids, as shown in messages.xhtml:

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
    </head>
    <body>
        <div id="msg1">
            <h3>Message</h3>
            <p>This is a message describing meaningful, signficant and important
                content ... really!</p>
            <p>
                <i>Along with a completely unimportant and irrelevant
                    message.</i>
            </p>
        </div>
        <div id="msg2">
            <h3>A second message</h3>
            <p>Here's an even more basic message that the previous one, perhaps
                not quite as insightful, but nonetheless still relevant.</p>
            <p>
                <i>Along with another completely unimportant and irrelevant
                    message.</i>
            </p>
        </div>
        <div id="msg3">
            <h3>The final message</h3>
            <p>This is the end-all and be-all (or at least end-all) of the
                messages. This is it, there ain't no more.</p>
            <p>
                <i>Except this message, of course.</i>
            </p>
        </div>
    </body>
</html>    

The code in the binding has also changed, in this case, making an AJAX call to retrieve the content, then parsing the URL to determine whether it includes a hashed id indicator. If it does, then the document retrieves a copy of the node corresponding to that particular entity, otherwise it just clones the entire document. Either way this new node is then appended to the content node, just as in the previous example. This is shown in the new binding output-type-xhtml:

<xbl:binding id="output-type-xhtml"
    extends="chrome://xforms/content/xforms.xml#xformswidget-base">
    <xbl:content>
        <span style="display:none;">
            <xbl:children/>                
        </span>
        <div anonid="content">
        </div>            
    </xbl:content>
    <xbl:implementation implements="nsIXFormsUIWidget">
        <xbl:constructor><![CDATA[
]]>
        </xbl:constructor>
        <xbl:method name="refresh">
            <xbl:body><![CDATA[
    var component = this;
    var url = this.accessors.getValue();
    urlArr = url.split('#');
    path = urlArr[0];
    hashId = urlArr[1];
    var http = new XMLHttpRequest();
    http.open("GET",path,true);
    http.onreadystatechange = function(){
        if(http.readyState == 4){
            var xmlDoc = http.responseXML;
            if (hashId != null){
                var elt = xmlDoc.getElementById(hashId).cloneNode(true);
                }
            else {
                var elt = xmlDoc.documentElement.cloneNode(true);
                }
            var content = document.getAnonymousElementByAttribute(
                 component,"anonid","content");
            while (content.firstChild != null){
                content.removeChild(content.firstChild);
                }
            content.appendChild(elt);                            
            }
        }
    http.send(null);
   return true;
]]></xbl:body>
        </xbl:method>
    </xbl:implementation>
</xbl:binding>                
            

which is also contained in the XFormsExtensions.xml file.

The last example I give with a certain degree of trepidation, because while it opens up whole avenues of development it also has the potential to break the spirit of XForms, because it provides a way to introduce scripted content into the XForms model that may produce potentially disastrous side-effects. It is, again, an extension of the <xf:output> object, but in this particular case nothing is actually visually displayed. Instead, it provides functionality similar to the <xf:setvalue> command, but in this case takes the referenced node (or its value), passes this to a JavaScript call, then if a target XPath expression relative to the bound node is given, places the result into the node given by the expression.

An example of how this can be called is shown in Listing 4, xformsXBL3.xhtml:

<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:ev="http://www.w3.org/2001/xml-events">
    <head>
        <title/>
        <style type="text/css"><![CDATA[
@namespace xf url('http://www.w3.org/2002/xforms');
xf|output[javascript] {-moz-binding:url(
        'xformsExtensions.xml#output-javascript');}            
]]></style>
        <script type="text/javascript">
var sigDigits = Math.pow(10,6);
function dsin(angle){
   return Math.floor(Math.sin(Math.PI * angle/180) * sigDigits)/sigDigits;
}            
function dcos(angle){
    return Math.floor(Math.cos(Math.PI * angle/180) * sigDigits)/sigDigits;
}            
function dtan(angle){
    return Math.floor(Math.tan(Math.PI * angle/180) * sigDigits)/sigDigits;
}            
        </script>
        <xf:model>
            <xf:instance>
                <data xmlns="">
                    <angle>45</angle>
                    <sine>0</sine>
                    <cosine>1</cosine>
                    <tangent>1</tangent>
                </data>
            </xf:instance>
        </xf:model>
    </head>
    <body>
        <xf:output ref="angle" javascript="dsin(current())" 
                target="../sine"/>
        <xf:output ref="angle" javascript="dcos(current());" 
                target="../cosine"/>
        <xf:output ref="angle" javascript="dtan(current());" 
                target="../tangent"/>
        <xf:input ref="angle" incremental="true">
            <xf:label>Angle: </xf:label><br/>
        </xf:input>
        <xf:output ref="sine">
            <xf:label>Sine: </xf:label><br/>
        </xf:output>
        <xf:output ref="cosine">
            <xf:label>Cosine: </xf:label><br/>
        </xf:output>
        <xf:output ref="tangent">
            <xf:label>Tangent: </xf:label><br/>
        </xf:output>
    </body>
</html>                
            
xformsXBL3.png

The particular nodes that support the JavaScript transactions are defined (in CSS) by having the javascript attribute. This can invoke any JavaScript function (or evaluate any expression) including functions that are defined within the global context of the page. This is demonstrated here with the use of the dsin (Degree Sine), dcos and dtan functions, which are defined in the script block at the beginning of the XHTML file.

The behavior defines three functions which can be used to access important properties:

  • current(). This returns the value of the currently bound node as a string,
  • currentNode(). This returns the bound node itself, and can be used to perform navigation relative to the node within the larger model,
  • instance(id). When passed the id of an instance element, this returns the current instance node, which may differ from the original instance node downloaded from the web.

These are JavaScript functions that exist within the scope of the binding, so you don’t need to worry about global functions of the same name overriding them.

The <target> attribute creates a new binding - once the javascript expression evaluates, if a target is defined (using XPath notation), then the result of that evaluation is placed into the target node. Note that if no target node is specificied, the JavaScript expression will still be evaluated (and any side effects run) but no direct assignment into the model takes place.

The behavior for making this work is relatively simple, and is shown in Listing 6, output-javascript.

<xbl:binding id="output-javascript" 
    extends="chrome://xforms/content/xforms.xml#xformswidget-base">
    <xbl:content>
        <span>
            <xbl:children/>
        </span>
        <span anonid="content"> </span>
    </xbl:content>
    <xbl:implementation implements="nsIXFormsUIWidget">
        <xbl:constructor>
            this._escapeUpdate = false;
        </xbl:constructor>
        <xbl:method name="refresh">
            <xbl:body><![CDATA[
    if (!this._escapeUpdate){
        var boundNode= this.accessors.getBoundNode();
        var js = this.getAttribute("javascript");
        var target = this.getAttribute("target");
        var xpe = new XPathEvaluator();
        var xpr = xpe.createNSResolver(boundNode);
        var xpResult = xpe.evaluate(target,boundNode,xpr,0,null);
        var targetNode = xpResult.iterateNext();
        function current(){
            return boundNode.textContent;
            }
        function currentNode(){
            return boundNode;
            }
        function instance(id){
            var instanceNode = document.getElementById(id);
            var modelNode = instanceNode.parentNode;
            return modelNode.getModelInstance(id);
            }
    
        var str = new String(eval(js));
        if (targetNode != null){
            targetNode.textContent = str;
            }
        this._escapeUpdate = true;                        
        var models = document.getElementsByTagNameNS(
                this.XFORMS_NS,"model");
        for (var index=0;index != models.length;index++){                        
            var model = models[index]; 
            model.rebuild();
            model.recalculate();
            model.revalidate();
            model.refresh();
            }
        this._escapeUpdate = false;
    }
    return true;
]]></xbl:body>
        </xbl:method>
    </xbl:implementation>
</xbl:binding>
                
            

The refresh() method here can be broken into roughly three parts. The first part retrieves the values from the attributes, and converts them into objects. This section includes the use of the XPathEvaluator to perform the XPath on the initial bound context node in order to retrieve the target nodes. Notice that this makes the assumption that the desired target node is within the same XML tree as the initial node - I leave it as an exercise for the reader to integrate an XPath instance method in order to extend the search outside of the initial tree.

The second part of the method defines the JavaScript current(), currentNode(), and instance() methods to be evaluated within the JavaScript expression, then evaluates this expression and (if a target has been defined) assigns it. Please note that the use of the eval() here has the potential to be a security hole, so some thought should be given to sanitizing any expressions before evaluating them.

The final block starts with the setting of the this._escapeUpdate property. This property solves a rather thorny problem. In order to recalculate and update the form, each model must run the four methods rebuild(), recalculate(), revalidate() and refresh(). However, normally, in doing so, this would also cause the <xf:output> objects itself to refresh, which would launch this object’s refresh method again, and eventually cause a stack overflow.

The solution here is straightforward - the object defines the _escapeUpdate property and initially sets it to false. During the course of the first refresh(), this property is set to true prior to invoking the refresh method for the model, which means that if the model is currently updating, then the refresh call will encounter the initial if test and fail through. Once the model has been updated (here a synchronous operation) then the property is set back to false.

The approach taken care solves a number of the more vexing issues when dealing with XForms - the lack of a formal extensible mechanism that can be accessed from within XPath, the inability to invoke external function calls when a critical property changes, and ways of making the UI components even more interactive, but this comes at something of a price in terms of debugging and code development. In general, if you do use this approach, avoid side-effects that may transparently change the data model or otherwise affect the operation of XForm components.

The State of the XForms Industry

I’ve worked fairly extensively with AJAX, and the current deep interest in AJAX programming has made a lot of people more cognizant about a number of deep seated design issues that seem to define the current state of software development.

  • Distributed programming, in any guise, is hard, and only by keeping programming at the endpoints relatively simple can you manage to keep all but the most basic web applications from unravelling. This usually translates into a need to keep frameworks small, lightweight and manageable, always a challenge when the underlying trend in most frameworks is to increase complexity or rigidity in the environment.
  • Declarative systems, whether embodied by XML, JSON, YAML and so on, provide a way of letting people manipulate complex objects without needing to impute semantics to those objects. The more you can avoid resolving semantics until absolutely necessary, the easier it is to deal with the transport and transformation of such code, and the more clearly decoupled such applications tend to become.
  • Declarative systems are inherently secure, until such point as you resolve the semantics of the system (in that respect they are a lot like quantum entities that maintain a multiplicity of states until such time as you open the lid on the box to determine whether you have a very dead or a very pissed cat). Of course, such declarations are fundamentally useless until you do resolve semantics, so it behooves systems developers to insure that your XML objects (or other declarative entities) are clean and safe before you impute semantics onto them.
  • Imputing semantics generally requires the use of some binding language. The more that you can minimize the need for these bindings to be public, the more stable and secure your code will be, and the less likelihood you will run into namespace collisions or unanticipated component interactions, something that tends to be a major problem with many JavaScript implementations.
  • This implies that, in order to reach a level of abstraction beyond simple “scripts”, regardless of the language, the imperative language (JavaScript, for instance) should in general support the bindings “beneath the covers” by creating a one-to-one relationship between the bound entity (the XML object) and its associated behaviors.
  • By that light, XForms, given that it both provides a mechanism for working with information in a model-view-controller manner, also has the advantage of being bindable - in other words, the language provides a set of pre-defined (and standardized) behaviors on abstract objects while at the same time opening up those objects to new ways of being rendered in the final presentations … in essence, letting users establish new behaviors on top of the old ones.

In other words, I see XForms as being an integral part of the future of such technologies as AJAX, as it provides a standard means of defining common behaviors while at the same time being extensible to allow for new behaviors. There is a tendency among programmers to look upon “competing” technologies as being all or nothing propositions - you either adopt XForms or you adopt AJAX, for instance - but I’m far more inclined to see XForms as being one of potentially many integral pieces that AJAX can use to establish more formal frameworks, especially given that AJAX by its very nature is largely the use of existing open standards (XHTML, JavaScript, CSS, XML, XMLHttpRequest, etc.).

Let me state that again in a slightly simpler fashion - XForms is part of the future of AJAX - providing a cohesive and time-tested framework at a time when the AJAX community is desperately trying to come up with one.

By itself, XForms is an interesting technology but one that might potentially always be a “specialist tool”. AJAX, while powerful, has security problems, lacks the mechanisms to abstract (or scale) well, and runs into implementation problems that will likely always be an intrinsic brake to the language’s adoption. Together I think the two technologies complement one another well, providing a powerful combination that can be readily adopted on any browser or stand-alone platform.

I see the Mozilla implementation as being a proof of concept that, once demonstrated, will likely prove attractive to other browser vendors and developers as well, for quite a number of reasons. The ability to make better forms is of course a part of this, a part that is likely to prove far more attractive to enterprise managers than it will the MySpace crowd, but realistically so much of what we currently use browsers for ultimately comes down to the expressive display of complex information, which is what forms are all about.

For instance, a few days ago I was at my local library and using the online catalog to find some science fiction books written by L.E. Modessit (one of my favorite authors, and well worth the reader). The interface was written for output on a Mozilla browser running on a Linux system. However, it was painfully slow, required navigation in ways that were neither intuitive nor always predictable, and I suspect that the Greater Victoria Library System likely paid a pretty penny to have it developed.

An XForms solution would have made it possible to separate the GUI presentation logic from the data-binding, minimizing the laboriously long waits as the server spent time generating complex markup. Indeed, at least a significant proportion of the application could have been downloaded just once, then repopulated with new content simply by changing the source of the data instance — without the need of rebuilding each page from scratch. It would likely, at least in the hands of a decent XForms developer, have taken a third or less of the time it took to create the server-centric one, and by moving most of the presentation logic to the client using a declarative structure, the application would have at least seemed faster and more responsive.

Admittedly, today, those XForms developers are few and far between. I don’t see this staying the case, however. Ever more data is being moved into XML - whether as data objects, documents, configuration resources or transport protocols - and as this process continues, “holistic” solutions that are XML aware at the pre-semantic level will tend to trump imperative solutions which attempt to impose semantics too early, even up to DOM manipulating code.

The presence of XForms in Mozilla natively, and through AJAX frameworks such as Orbeon non-natively, mean that people can create fairly sophisticated application GUIs without the need to ship large binaries or have Java or ActiveX support enabled … and can do it without having to worry about distribution costs or licensing restrictions. Coupled with binding languages, the expressiveness of XForms improves dramatically as well, letting you do with one well placed tag and a behavioral declaration what might take hours and lots of debugging headaches with other platforms - and because you can create such libraries of behaviors this becomes a solution which is scalable from both a development and a deployment standpoint.

In the end any web solution lives or dies based upon the degree to which it reduces development costs while improving performance. Given the benefits, I see XForms becoming very big within the next few years, perhaps in many ways as important as XHTML itself will likely end up being.

Tomorrow and tomorrow and tomorrow … I’ve begun developing commercial applications around XForms, something which I will discuss in a few months when it might less jeopardize the endeavors, but I keep coming back to this interesting paradox. The applications which I build exist almost exclusively within the constraints of the XML space. The server side code I need is lightweight to the point of absurdity, coming as it did from a decision to avoid getting wrapped up in frameworks. I transform code with XSLT and EXSLT, perform validation of business logic with schematron and more transformations, generate forms from schemas balanced by a separation of presentation layers via CSS, use XForms and XBL on the client to build the interfaces and marshal the results, again coupled with the occasional transform or query, and I use an XQuery interface and some limited Sparql processing to provide some semantic business rules constraints.

The curious thing is that the applications, ones that in other frameworks end up taking man-years and are notoriously brittle, seem to naturally flow out of the movement of the XML through the system. I’ve written in the past about the kudzu nature of XML - that once you introduce XML into a system it tends to induce a phase shift within that system, replacing complex semantics with neutral abstractions and just-in-time semantic resolution.

XForms is a key to this process - once you introduce it into your systems you’ll wonder why you spent so much time wrapped up in imperative frameworks. Especially in conjunction with both XHTML and some kind of a binding language such as XBL, XForms brings a means of building and distributing applications cleanly, reducing your dependency upon server side parsing of text strings and the expensive process of maintaining complex session state on servers.

The XForms solution out of Mozilla has been the focus of this series, but there are other implementations out there. Orbeon is an AJAX based XForms implementation that can be run effectively on Internet Explorer (and I believe they either have or have in the works a Mozilla implementation). I’d heartily recommend it in those cases where you need cross-platform AJAX support.

IBM recently acquired PureEdge, a forms based solution that includes an XForms implementation, and is now marketing the product as the IBM Forms ??. A number of key people (and colleagues that I have a lot of respect for) are involved with this particular product, including John Boyer, the current editor of the XForms 1.1 specification for the W3C.

X-Port’s FormsPlayer engine was one of the first XForms engines that I played with, nearly five years ago now, and it is still one of the best such engines for use within Internet Explorer. Mark Birbeck, the architect of the original application, has been heavily involved with the W3C’s XForms efforts.

Open Office 2.0 also has a remarkably robust XForms engine, one which is remarkably capable of generating sophisticated forms using a WYWSIWYG forms editor, and I will be writing additional articles about utilizing the XForms engine shortly.

There are a number of others. I am planning, in the near future, to cowrite a benchmark suite comparing performance, compliance and utility of various XForms engines, as the field is now getting robust enough that such studies are dealing with mature products and projects rather than betas and one-offs.

Launching XForms.org

Given all of this, I was fortunate in getting the chance to acquire the domain xforms.org. There are a few domains which I see as being both primal and that have the potential to become major nexus points on the web, and I believe strongly that this is one of them. To that end, as I’ve been working on this series I have also, in the background, been working on creating a portal at www.xforms.org that will be a focal point for covering news of the XForms industry, benchmark studies, code implementations , business articles and viewpoints and similar works.

It’s purpose is simple - I want to see XForms succeed. I want to encourage the adoption of the open standard, I want to see people who work hard building implementations or mastering the intricacies of developing applications with XForms get recognized for their work, I want to see companies that have bet the farm on bringing XForms to the masses prosper, and I want people to have a place where they can learn how to use the technology.

The site is still in its infancy - I am attempting to balance getting it launched with other outstanding obligations, but I plan to have discussion groups (with mail-list support), newsfeeds, and sample code repositories up shortly. I want this to be the nucleus for a new XForms development community, one that’s open to all people and that, while I hope to address issues pertinent to specific implementations, will nonetheless be open to people working with all implementations.

What I am seeking now are people who would be interested in writing blogs or articles, companies that would be interested in setting up sections within the site to promote their own products, and people willing to pass on news about their XForms related applications. If you are interested in any of these, (or if you are interested in getting an xforms.org email address) please contact me at kurt.cagle@xforms.org..

For those of you who have stuck with me through this series, I wish to express my appreciation, and a request that you contact me as well to express your thoughts on what you’d like to see in subsequent series and columns. I think the time for XForms is nearly at hand, and it should be an interesting ride …


Kurt Cagle is an author, technology evangelist, and software developer specializing in XML, AJAX and web technologies. He lives in Victoria, BC, where he is helping to coordinate the SVG Open 2006 conference (more information about which will be in the next column).