This is the second in a series of articles I’m writing about the ongoing XForms implementation in Mozilla Firefox, with the previous article being Why XForms Matters, Revisited. Then next article in the series is Understanding XForms: Components

When you talk to people who’ve heard about XForms, they like the idea in theory … until they encounter an actual XForms example. There’s a brief period of shock, a momentary glazing of eyes, then inevitable the utterance, “but it’s so … complicated!” Then they run off to the WHATWG Web Forms 2.0 project, and continue to spend man-years attempting to script what they could have had free.

It hasn’t helped that some of the most prevalent examples have been things like calculators, especially since calculators can actually be implemented in far easier fashion with straight Javascript on an ordinary HTML form, with XForms being overkill for it. The other “canonical” example is a W2 Form - and to be perfectly honest, while this actually is a better use of the technology, it is far too complex to be very canonical.

What I wanted to look at in this particular article is a much simpler walk through to put together an XForm based application that illustrates that it really isn’t that difficult to create an XForm - you just have to have an understanding of what exactly XForms really are.

One of the first things that people do when they start exploring XForms is to look for something like a <form> element. They will have trouble finding it for the very simple reason that it doesn’t exist. This represents one of the biggest differences between HTML forms and XForms. The purpose for the form element is simple - it acts as a container for all of the fields within it. In essence, these fields in aggregate make up a model. When you fill in a given field within the form, you are creating a hypothetical association between the input element and some piece of the model.

However, the model in question has a number of real limitations:

  • You have a flat data model, so there is no way to implicitly create repeating relationships that are deeper than one item unless you hack something into the component names.
  • You have the awkwardness of having model names and ids being each bound to the form component, a distinction that can make coding difficult
  • There’s no clean way of populating the fields from the model without having to resort to fairly complex Javascript coding that creates too much dependency between model and presentation.

The XForms model, on the other hand, works by assuming that was important is not some generalized form container, but the model that the form is intended to represent. If that model was given as an XML instance, then any form control could tie directly into the model, irregardless of where the model was in the page. For example, consider a very rudimentary XForms page.

<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"
    xmlns:d="http://www.mydata.com/xmlns/data">
    <head>
        <title/>
        <xf:model>
            <xf:instance id="user_profiles">
                    <d:user>
                        <d:firstname>Kurt</d:firstname>
                        <d:middleinitial>A</d:middleinitial>
                        <d:surname>Cagle</d:surname>
                </d:user>
            </xf:instance>
            <xf:submission action="http://example.com/submit" method="post"/>
        </xf:model>
    </head>
    <body>
        <xf:input ref="d:firstname">
            <xf:label>First Name: </xf:label>
        </xf:input>
        <xf:input ref="d:middleinitial">
            <xf:label>MI: </xf:label>
        </xf:input>
        <xf:input ref="d:surname">
            <xf:label>Last name: </xf:label>
        </xf:input>
        <xf:submit>
    </body>
</html>

There are several important things that can be gleaned from this sample, as basic as it may seem. The first is the fact that the model in this particular case, is situation not in the body (as is implicitly the case with HTML Forms) but in the head. It doesn’t need to be, but given the model is by itself an unrendered object - metadata in the purest sense of the word, having this in the head of the document makes sense.

You have within the model at least one (and possibly multiple) instances, each of which should be valid XML content. What’s more, that content needs to be in its own namespace. That may seem like an onerous requirement, but from a compound document standpoint, it makes a lot of sense. The model doesn’t have anything to do with XHTML, and doesn’t really have anything to do with the XForms namespace. It is a description of some other entity unrelated to either, a separate namespace, so should be designated as such.

I suspect that a lot of the confusion that people have when dealing with XForms actually arises from the namespace prefix, which has the side effect of making code look much more verbose than it really is. This same phenomenon arises with XSLT, which also is comparatively simple in structure but is confusing to the layman because of the namespace prefixes (largely, I suspect, because we all tend to read xf:foo as the foo folder or file sitting on the xf drive, not as the foo name in the xf associated namespace.)

The content within the instance should be a well formed XML object - you can’t just put a sequence of elements in place within the same instance. What you get for this bit of dilligence is a starting point for the instance, or, in the vernacular, a context. The first such model instance is treated by the XForms engine as being the default context, with the first element in the instance (in this case the <user> element) being the default starting point for every subsequent reference (given by the ref attribute in each of the components. Thus, if you look at the input block for the firstname field,

        <xf:input ref="d:firstname">
            <xf:label>First Name: </xf:label>
        </xf:input>

you can see that the ref in question points to “d:firstname”. This is an abbreviated XPath reference, relative to the default context. In this particular case, this is equivalent to:

        <xf:input ref="/d:user/d:firstname">
            <xf:label>First Name: </xf:label>
        </xf:input>

where the starting slash indicates the absolute root of the document.

If you have multiple models in the document, or if you wish to explicitly state the datasource, you can use the model property explicitly establish the model. For instance, given that the above example is tied to the model with instance user_profiles, you could formalize the first statement as:

        <xf:input ref="/d:user/d:firstname" model="user_profiles">
            <xf:label>First Name: </xf:label>
        </xf:input>

Of course, in HTML, you could simply assign values to input elements using the value attribute, so it seems like an incredible amount of work for what seems like a simple operation. However, this work pays off for itself pretty quickly, once you understand the fact that in most cases its likely that most of the model will usually not be in the web page. That sounds a little cryptic, but what I mean here is that in general, your model will likely be an XML resource on the server, rather than something embedded within the web page itself. For instance, suppose that you had an external file on the server called user.xml:

<d:user xmlns:d="http://www.kurtcagle.net/xmlns/data">
    <d:firstname>Kurt</d:firstname>
    <d:middleinitial>A</d:middleinitial>
    <d:surname>Cagle</d:surname>
</d:user>

then you could reference it as follows:

<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"
    xmlns:d="http://www.mydata.com/xmlns/data">
    <head>
        <title/>
        <xf:model>
            <xf:instance id="user_profiles"  src="user.xml"/>
            <xf:submission action="http://example.com/submit" method="post"/>
        </xf:model>
    </head>
    <body>
        <xf:input ref="d:firstname">
            <xf:label>First Name: </xf:label>
        </xf:input>
        <xf:input ref="d:middleinitial">
            <xf:label>MI: </xf:label>
        </xf:input>
        <xf:input ref="d:surname">
            <xf:label>Last name: </xf:label>
        </xf:input>
        <xf:submit>
    </body>
</html>

If this user.xml file was a static file, then frankly this wouldn’t provide that much benefit. On the other hand, if that content is dynamically generated (and can be parameterized) then what you have here is the equivalent of an AJAX script talking to a web service, in considerably fewer lines of code. Additionally, this process occurs asynchronously, filling up content in the background even as data is being loaded on the server, simplifying the need to write multiple asynchronous script handlers as a consequence.

One final aspect of this simplified example is the use of the submission element at the end of the model definition:

<xf:submission action="http://example.com/submit" method="post"/>

Because you do not have a formal <form> element within the XForms language, this submission element serves the function of identifying the server where (and how) the content will get posted instead. The upshot of this is that when the user presses the submit button, it sends the contents of the revised XML model to the server. For instance, if you typed “Anne” into the firstname field, “L” into the middle initial field and “Martin” into the “surname” field in the displayed XForm, then each of these fields will automatically update the corresponding model, such that:

<d:user>
    <d:firstname>Anne</d:firstname>
    <d:middleinitial>L</d:middleinitial>
    <d:surname>Martin</d:surname>
</d:user>

gets posted to “http://example.com/submit” using the HTTP POST protocol. The <xf:submit> button is one way to initiate this post, but there are a number of others which will be covered in subsequent articles in this series.

This should hint at both the power and the occasional complexity of XForms. In my next XForms post, I will be covering the various UI components in considerably more depth.

Kurt Cagle is an author and web developer living in Victoria, British Columbia.