Summer’s been fairly brutal throughout much of both the US and Canada the last few weeks,
and transplanted American that I am I have to admit that I’m beginning to appreciate
what 35°C really means and that it’s a lot warmer than one might
expect - a sweltering (for Victoria) 95° F. As Victoria is on an island that
usually has most extremes of temperature moderated by sea breezes and is positioned on
the largely leeward side of the island, it says altogether too much about the wave of
heat that has had most of the continent in thrall … and yes, I say this knowing full
well that I’m about to receive all kinds of brickbats from those of you who’ve been
toughing it out in 110° F (or a mind-boggling 43°C) temps that have hit
much of the plains.
I gave a keynote address on SVG last week at the GeoWeb conference in Vancouver, and will be sharing my remarks from that shortly. Today, I’d like to give you the fifth installment about XForms, of six - this has been a remarkably well read series, which gives me a certain amount of hope for the specification. I should be making an announcement shortly concerning XForms in this space …
Trigger Happy
In the last column, you may have noticed that there was a singular lack of discussion about one of the most basic of all components - the button. Now, this may seem like a particular striking omission (attributable perhaps to writing these columns way too late at night) but in fact there was a bit of method in madness.
One of the most striking things about a button is the fact that, unlike a slide, input box, select box, or output field, a button does not in general reflect state (I’ll deal with the special use case of toggle buttons in a bit). Instead, when you press a button, in general what you are doing is initiating an action - you are changing the state in the rest of the application, in essence.
This notion informed the terminology of XForms: unlike in traditional HTML you have no
<xf:button> element. Instead, you have the
<xf:trigger> element, which “triggers” a particular
action to occur. Such a trigger is similarly conceived of as being an abstract element,
though most XForms implementations (including Mozilla Firefox) represent such a trigger
as a button.
In HTML, the event which you use to pick up the press of a button is almost invariably
the click event, (usually throught the onclick event handler). However,
XForms makes some fundamental assumptions about how you will interact with the
environment, and one of the most critical is that you should never assume that the only
mechanism (or even an acceptable mechanism) in use is a mouse. Hitting an ENTER key,
speaking a command word, perhaps even using a psionic confabulator in order to
telepathically indicating that the action should occur are all considered viable (if
somewhat outre) ways of interacting with the form, and consequently you should get away
from the mouse-centric viewpoint of the onclick handler.
In its place you get the highly intuitive DOMActivate event (okay, their hearts were in the right place, anyway). This event basically says that whenever you click on the control, it will automatically “activate” and perform the indicated action. Oh well.
So what, you ask, is this particular indicated action? Or more properly, the question is - so when you press the button, where does the particular script block go? This is when the XForms gurus look at you with a curious smile on their face and say “Please, young grasshopper … what is this ’script block’ that you are talking about?” or perhaps “Oh, foolish grasshoppers, you place to much emphasis on the doing, not the being.” or even “What is the sound of one glorp clapping?” … but only if they’ve been sniffing some really interesting incense.
In point of fact, the primary actions supported by XForms are declarative, written in XML
as a block contained within an <xf:action> element within the
trigger. For instance, consider a simple counter - pressing a button increments a field
(xformsEvent1.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 id="dataStore">
<data counter="1"/>
</xf:instance>
</xf:model>
</head>
<body>
<xf:trigger>
<xf:label>+</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="@counter"
value="(instance('dataStore')/@counter)+1"/>
</xf:action>
</xf:trigger>
<xf:output ref="@counter"/>
</body>
</html>
Once again, the XForms approach differs considerable from the normal HTML approach. In the HTML approach, the control displaying the content would also contain the content. However here its the model that holds the value (an attribute named counter) and the control only acts as a means to display this value.
To the trigger itself - the trigger starts out with a label that contains the contents to
be displayed, which in this case will be displayed on the button face itself. Below that
is the <xf:action> element. This is in essence simple a
grouping device, and is not strictly speaking in the case of a single action to be
performed. What is important here is that either the action or the control itself should
contain the name of the event which “trips” the trigger - here the rather oddly named
“DOMActivate” element. The events themselves are in a separate namespace
xmlns:ev="http://www.w3.org/2001/xml-events", reflecting the use of the
W3C’s xml-events. Note that as with most namespaces the use of the “ev” prefix isn’t
required - you could just as readily call it event: or evt:
(or snorg: for that matter) but it has become conventional.
The actual action is contained in this case in the <xf:setvalue> statement.
This particular action first establishes a node context (here
ref="@counter", which determines which node in the model will receive the
result of the operation. The value attribute, in turn is an XPath
expression that evaluates to either a scalar value or an XML node. In this case, the
calculation is simple - retrieve the value already in the @counter attribute and add one
to it. When the action is invoked, the increment occurs, and the model then notifies all
of the form components that have links to @counter that they should update (in this case
the following <xf:output> should reflect this change.
Again the XForms approach is very classically MVC - you are not updating the output element directly. Instead, the output element only reflects the changes made into the model itself. This design pattern has a number of names, but is perhaps closest to the broadcaster/observer pattern where changes that are made to a data source automatically cause any objects with dependencies upon (interests in) those changes to be notified, and hence to update themselves.
This notation is a little unwieldy, and there are simplifications possible, but the notation also makes possible some interesting effects. For instance, suppose that instead of a plus sign, you wanted two buttons - a happy face button indicating that an increment should occur, and a sad face button indicating that a decrement action should occur. The label in this particular case (and in fact in general) can take any HTML content, including text formatting and images, and place it on the button face. Thus, the new counter can be revised from the old as follows ( (xformsEvent2.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 id="dataStore">
<data counter="1"/>
</xf:instance>
</xf:model>
</head>
<body>
<xf:trigger>
<xf:label><img src="imagesbu/2.gif"/><br/><b>Decr</b></xf:label>
<xf:setvalue ref="@counter" value=". - 1" ev:event="DOMActivate"/>
</xf:trigger>
<xf:output ref="@counter"/>
<xf:trigger>
<xf:label><img src="imagesbu/1.gif"/><br/><b>Incr</b></xf:label>
<xf:setvalue ref="@counter" value=". + 1" ev:event="DOMActivate"/>
</xf:trigger>
</body>
</html>
The first thing to notice in this situation is the use of smiley (or sad) faces and text within the label, as discussed above. This content can be pretty much anything that can be expressed within HTML or SVG. The button will resize itself to fit the content within it, which means that you could theoretically create buttons that hold whole web pages or screen-sized images and they would display appropriately.
Perhaps more intriguing here is the <xf:setvalue> statements
here. Because there is only one such statement, the <xf:action> grouping
statement is not necessary. However, some way of tracking the event is
necessary. Thus, the event has been moved directly onto the <xf:setvalue>
statement itself.
Additionally, the complex instance() statement is gone, replaces with “. - 1″ and “. + 1″
respectively. The XForms parser assumes that it is likely that the action being
performed on a given node in the model will relate in some way to that node, so the
value statement evaluates in the context defined by ref.
Since the context is already the @counter attribute, specifying “@counter -1″ would in
fact try to find the counter attribute of the counter attribute. Instead,
you can use the current node operator “.” to indicate the current context node. While it
can make such XPath expressions a little less clear, it usually can make them more
concise.
Getting the Message
Suppose that you wanted a message to pop up when you clicked on a particular button - an
indicator of why the various happy/sad faces are in those states, for instance. XForms
can help you considerably there. For instance, the
<xf:message> element can be placed within an action block and
will thus be automatically invoked whenever the button is pressed (xformsEvent3.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 id="dataStore">
<data counter="1"/>
</xf:instance>
</xf:model>
</head>
<body>
<xf:trigger>
<xf:label><img src="imagesbu/2.gif"/><br/><b>Decr</b></xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="@counter" value=".-1"/>
<xf:message level="modal">You are giving the Glorp less food
(food = <xf:output ref="@counter"/>) and that makes it sad.</xf:message>
</xf:action>
</xf:trigger>
<xf:output ref="@counter"/>
<xf:trigger>
<xf:label><img src="imagesbu/1.gif"/><br/><b>Incr</b></xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="@counter" value=".+1"/>
<xf:message level="ephemeral"><div style="width:200px;">
<img src="imagesbu/1.gif"/>You are giving the <b>Glorp</b> more food
(food = <xf:output ref="@counter"/>) and that is making it happy.</div>
</xf:message>
</xf:action>
</xf:trigger>
</body>
</html>
Here, the value of <xf:action> becomes more obvious - the
message object is a form of action (and normally it would take an ev:event
attribute, but because it’s now within the scope of the
<xf:action> object, the event handler is assumed. When the
DOMActivate event is invoked, a message will pop up giving some basic information. These
messages are halfway between tooltips and formal dialogs and come in three flavors:
- modal. The (more or less) standard alert box, which can display limited text markup but not images. This stays until it’s dismissed, and no other actions can occur while it is up.
- modeless. Similar to a modal dialog in form, but you can interact with the calling page. This is very useful for help content, as you can both see and copy and paste correctly formatted content from the dialog.
- ephemeral. This is something like a tooltip - it stays up for a limited period of time or until clicked, then disappears. The power of the ephemeral dialog, however, is that you can place rich content (including pictures) into it, making it a potentially useful vehicle for creating context menus and other floating content.
The message dialogs are a direct response to the blocking actions of the normal JavaScript alert() command, which is often used by developers to report status messages even at the cost of pausing the program. By making dialogs modeless, you can alert your users to a problem without forcing them to respond while the ephemeral message works even better at providing temporary status messages that go away spontaneously when ignored.
Pay close attention to the fact that you can in fact use
<xf:output> (and other controls) within these dialogs. This
means that rather than hard coding messages, the messages can be generated in such a way
that they contain more detailed information about the particular problem or issue
involved. Similarly, though not shown, you can use the
<xf:message> statement with a ref attribute to
pull content directly from the data model.
Valid Arguments
Shifting to setvalue nodes for just a second, it’s worth noting here that you can constrain the actions of these nodes through the use of calculate bindings. For instance, you couldn’t provide less than zero food pellets to your poor glorp, so you need to have some realistic way of assuming that you cannot go negative on the decrements. Similarly, you may have only so many food pellets available to give at any given time, so there may be an upper bound to the values as well.
You can use the XForms if() statement to check to insure that you are in fact neither going below or above the requisite boundaries. These could be placed in the setvalue commands, such as:
<setvalue ref="@counter" value="if(. < 1,0,. - 1)"/>
in which case this will automatically reset the value to 0 if you attempt to drop below that.
On the other hand, given that bind statements automatically apply any time a referenced object gets changed, you could also pass the constraints directly into the binding, as follows (xformsEvent4.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 id="dataStore">
<data counter="1" minval="0" maxval="5"/>
</xf:instance>
<xf:bind nodeset="@counter" calculate =
"if(.<= ../@minval,../@minval,if(.>= ../@maxval,../@maxval, .))"/>
</xf:model>
</head>
<body>
<xf:trigger>
<xf:label><img src="imagesbu/2.gif"/><br/><b>Decr</b></xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="@counter" value=". - 1"/>
</xf:action>
</xf:trigger>
<xf:output ref="@counter">
</xf:output>
<xf:trigger>
<xf:label><img src="imagesbu/1.gif"/><br/><b>Incr</b></xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="@counter" value=". + 1"/>
</xf:action>
</xf:trigger>
</body>
</html>
However, ideally, you should be able to take advantage of the fact that XForms can internally determine when it’s reached an invalid state and correct itself. This is where the xforms-invalid event comes in. This is a form-level event (rather than one associated with a given component) and is fired whenever the form ceases to be valid. An example of how such a form could work is shown in xformsEvent5.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">
@namespace xf url("http://www.w3.org/2002/xforms");
xf|output:invalid .xf-value {color:red;}
</style>
<xf:model>
<xf:instance id="dataStore">
<data counter="1" minval="0" maxval="5" />
</xf:instance>
<xf:bind nodeset="@counter"
constraint="(. >= ../@minval) and (. <= ../@maxval)">
</xf:bind>
</xf:model>
</head>
<body>
<xf:action ev:event="xforms-invalid">
<xf:message level="modal"><xf:output
value="if(@counter < @minval,
'You cannot have a negative number of pellets',
if(@counter > @maxval,
concat('You cannot have more than ',@maxval,' pellets.'),''
)
)"/>
</xf:message>
<xf:setvalue ref="@counter"
value="if (. <= ../@minval,../@minval,.)"/>
<xf:setvalue ref="@counter"
value="if (. >= ../@maxval,../@maxval,.)"/>
</xf:action>
<xf:trigger>
<xf:label><img src="imagesbu/2.gif"/><br/><b>Decr</b></xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="@counter" value=". - 1"/>
</xf:action>
</xf:trigger>
<xf:output ref="@counter">
</xf:output>
<xf:trigger>
<xf:label><img src="imagesbu/1.gif"/><br/><b>Incr</b></xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="@counter" value=". + 1"/>
</xf:action>
</xf:trigger>
</body>
</html>
The challenge with the XForms environment comes in dealing with a potentially large number of factors that can make a form invalid - in essence, unlike with procedural programming, the ability to catch exceptions in XForms 1.0 is somewhat limited, though this is addressed to a greater degree in the XForms 1.1 specification.
Of Links and Scripts
It’s easy to lose sight of the fact, when discussing XForms, that such forms are intended
to be used within the context of web content. Indeed, the ability to link - to replace
web page content with new content or to spawn a new web window, is actually a very well
supported action under XForms. This action is performed using the
<xf:load> element.
This element, like the <xf:setvalue> command, can work well
with both static links and ones directly (or derived from) the data model. The static
case is handled with the resource attribute, which contains a static link:
<xf:trigger>
<xf:label>XForms.org</xf:label>
<xf:action ev:event="DOMActivate">
<xf:load resource="http://www.xforms.org" show="replace"/>
</xf:action>
</xf:trigger>
In this particular case, clicking on the trigger (the button) will cause www.xforms.org
to load in place of the current web page. This fragment will render as a button with the
label XForms.org on it. However, interestingly enough, if you set the trigger’s
appearance attribute to "minimal", the button will be
replaced with an inline hypertext link, using the label as the text displayed. In
essence,
<p>Visit <xf:trigger appearance="minimal">
<xf:label>XForms.org</xf:label>
<xf:action ev:event="DOMActivate">
<xf:load resource="http://www.xforms.org" show="replace"/>
</xf:action>
</xf:trigger>!
</p>
is the same as
<p>Visit <a href="http://www.xforms.org">XForms.org</a>!</p>
raising the question about why you would need to go to such extremes to create a link in XForms. For the purely static case, the concern is probably merited.
However, the situation changes when you start dealing with dynamic links. The
<xf:load> element can take all the same single node binding
properties that <xf:output> and others can take, including ref
and bind. As an example, the following takes a link from the data model (xformsEvent7.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>
<xf:model>
<xf:instance>
<data src="http://www.xforms.org" title="XForms.org"/>
</xf:instance>
</xf:model>
</head>
<body>
<p>Visit <xf:trigger appearance="minimal">
<xf:label ref="@title"/>
<xf:load ref="@src" show="new" ev:event="DOMActivate"/>
</xf:trigger></p>
</body>
</html>
After the page is loaded, when the user clicks on “XForms.org” the link to that site is activated and launches
a new window (show="new") displaying that site.
You can also take advantage of the load command to launch simple JavaScript commands by using the
javascript: protocol.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xbl="http://www.mozilla.org/xbl"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
<title/>
<style type="text/css">
@namespace xf url("http://www.w3.org/2002/xforms");
</style>
<script type="text/javascript">
var notify= function(){alert('You just called the notify function.');}
</script>
<xf:model>
<xf:instance id="dataStore">
<data url="javascript:notify()"/>
</xf:instance>
</xf:model>
</head>
<body>
<p>
<xf:trigger>
<xf:label>Invoke Javascript call.</xf:label>
<xf:load ref="@url" ev:event="DOMActivate"/>
</xf:trigger>
</p>
</body>
</html>
What happens here is that the load command reads the @url reference
to retrieve the string 'javascript:notify()'. The javascript: protocol takes
the text after the javascript: command and evaluates it in the global JavaScript
context. This means that if other functions are defined in the page the evaluation
will call that function. Unfortunately, this does not pass an event object as part of the call, which
significantly limits the types of things that can be done with this approach, but it is good
for generalized scripts, especially when they come in as part of a data model.
The next logical jump from here is get into scripts that are aware of the objects invoking them, and that can in fact operate on the XML models themselves. In general the best way of calling these is to go back, once again, into the XBL binding layer, a discussion which I’ll defer to the next XForms column.
Kurt Cagle is an author, web architect and consultant specializing in XML, AJAX and Web 2.0 services. He lives in Victoria, BC and had learnt the fact that while -40° C = -40° F, 40° C most certainly does not equal 40° F


Kurt,
Years ago I was anticipating the advent of XForms and pushed it as a technology we should support at SilverStream. I saw it as a way to get away from the HTML form and its limitations. From what I know it was implemented at Novel, but really didn't gain much traction.
In a future blog or article I'd like to know what's going on in the XForms world. Like many XML technologies it seems to have been sucked up into the black hole of over engineered xml specifications that the XML community has trouble demonstrating. I'd love to hear more about where you think XForms is going and what it's usefull for. And it'd be refreshing on XML.com to see anything other than AJAX. I don't know who is in charge of XML.com, there was a change for the worse within the last year. With OWL, RDF, XMP, XForms, microformats, etc, there's so much to talk about on XML.com other than global warming, political blogs, and AJAX...and you and David P. seem like the last folks on the earth who understand this stuff.
Taylor
Taylor,
My impression on XForms is that its been in a period of quiescence that seems to hit a lot of W3C standards - there's a period of about 3-4 years where the technology gets announced, then seems to disappear into the abyss. It takes about that long for critical mass to be achieved, and for the technology to really start taking off again, I believe, but as an evangelist for the technology it can be frustrating biding one's time.
XML.com is, like most technical news outlets, focused on where the programmers are, and as much as I'm not that happy about it either, most of that lately seems to be AJAX. The formal editorial staff (of which I'm not a part) tends to look at articles that they know about as well, and since most tend to be old hands at programming XML within imperative structures, this is what ends up getting commissioned as articles. The blogger group, such as myself or David P., don't have that restriction (or get the money, for what its worth), so most of the articles that we contribute tend to reflect personal biases as much as anything. Given that I tend to like outlier technology, that does give me a vehicle to discuss everything that I want, so letters like yours are important because it tells me when I'm hitting the mark and what other areas need to be discussed in greater detail.
Incidentally, I'm (slowly) starting up a new site specifically dedicated to XForms - http://www.xforms.org. There's not a lot there yet (and I'm keeping news about it fairly low key until I can get a critical mass of articles there) but I'm hoping to make it a clearinghouse specifically for XForms and related technologies.
As to the Semantic Web technology, I occasionally dip my toe into that domain, but find that it tends to be fairly esoteric for most readers to understand, one of the reasons that I wade carefully there. Sparql opens up some interesting venues , however, and I hope to devote some future posts to it.
Finally, about the "off-topic" blogs ... I can't speak for others, but the blog I write for O'Reilly is meant to cover XML programming but also, occasionally, the context in which the programming happens. I'm a programmer - I want to know the bigger picture issues sometimes about whether my job - or the market for my job - will be there next year. I try not to stray too often into that territory, as you are correct in saying that the focus here should be on XML, but I think both voices are important. (As an aside, my most recent "political" post actually gets into the nature of long tail social phenomenon, which I think is actually very relevant in the world of large scale distributed programming, which is increasingly what I'm seeing XML actually representing).
Anyway, thanks for the feedback. T'is useful and much appreciated.
-- Kurt Cagle
sadf
Great article, but hey where's the follow up?
".. a discussion which I'll defer to the next XForms column."
Thanks for the article
mckamey
It was great reading this article excellent writing
parent
I learned a lot of info reading this article keep on this way
kulick
Hi this is really fine read. Looking forward for more of these articles.
amashit
Very informative.
Frane Milic
hi,
i wannato make a wizard using xforms , for that i want to show a block of controls when i click on the button.
Can u plz help me out in this.
i ll be very thankful to u .
Thnaks