xforms basics - the melonfire community - trog
TRANSCRIPT
Community
Trog
Copyright notice:
This article is copyright Melonfire, 2014. All rights reserved.
All source code, brand names, trademarks and other content contained herein is proprietary to
Melonfire, 2014. All rights reserved.
Source code within this article is provided with NO WARRANTY WHATSOEVER. It is meant for
illustrative purposes only, and is NOT recommended for use in production environments.
Copyright infringement is a violation of law.
Printed from http://www.melonfire.com/community/columns/trog/article.php?id=224
XForms Basics (part 1)Use XForms to manage the display, input and processing of form data on the Web.
X Hits The Spot
A year or two ago, XML was heard about more often than it was seen, a technology that was
sufficiently arcane enough to keep all but the most hardened geeks at bay. No more is this the case;
today, XML is most definitely in the mainstream, and proving its mettle by making all kinds of new
and unique applications possible (witness the success of Amazon.com's AWS service, or the Google
APIs, both based on XML technology).
XML isn't resting on its laurels, though. As the technology is becoming more and more popular, XML
development groups operating under the aegis of the World Wide Web Consortium are rapidly
inventing new and interesting ways to use it. One of the more interesting ideas is XForms, which
uses XML to manage the display, input and processing of user-inputted data on the Web.
If you're at all serious about using XML, you're going to need to understand XForms. And over the
course of this tutorial, I'm going to assist you in this endeavour by explaining the fundamentals of
the XForms data model, together with some examples of how it can be used.
Before we get going, though, a few disclaimers:
First, I don't claim to be an expert on XForms. Much of the material in this tutorial is based on my
own research with the XForms specifications and varied XForms implementations, or gleaned from
late-night email conversations over beer and stale pizza. In other words - caveat emptor!
Second, as new XML standards are proposed and disposed, the material here may become invalid;
you should always refer to the most current standard or recommendation for up-to-date
information. This tutorial is based on the W3C's XForms 1.0 recommendation dated 14 October
2003, at http://www.w3.org/TR/2003/REC-xforms-20031014/
Now that I have that off my chest - let's get started!
Out With The Old...
Before getting into the details of how XForms works, it's important to understand the context in
which it was developed, and the need and rationale behind it.
You know that HTML already allows user interaction with a Web application, through the use of
forms and associated form controls like text entry fields, checkboxes and radio buttons. However,
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=224
1 of 9 4/22/2014 8:14 AM
although HTML forms are simple to understand and easy to use, they do have a couple of
drawbacks:
1. HTML forms can usually be viewed (and used) only in a Web browser - they don't render too well
on handhelds, cellphones or other devices.
2. Processing form input in the Web world usually requires the services of a programmer, who must
code the business logic need for form data validation, input parsing and further data manipulation
and processing.
3. Unless you put in a great deal of thought at the design stage (and sometimes not even then),
HTML forms cannot be easily reused across different applications, or even within an application.
These drawbacks might seem trivial in the context of today's Internet - it ain't broke, you're
probably thinking, so why fix it? - but they assume serious proportions in the context of an XML
world, which is built around data and the relationships inherent in it.
...In With The New
XForms was designed to address these drawbacks, and also breathe fresh life into traditional
approaches to handling user input in a client-server paradigm.
If you take a look at the requirements document for XForms - it's available online at
http://www.w3.org/TR/xhtml-forms-req - you'll see that XForms was designed to enable the
"separation of the data being collected from the markup of the controls collecting the individual
values". Right at the outset, then, the XForms specification makes a clear distinction between the
form model (what the form does) and its controls (what it looks like).
A simple example of this might be a form which asks for your gender - in a Web browser, you'd be
presented with radio buttons or a drop-down list, while on a cellphone, you'd be asked to enter a
particular number corresponding to the choices. This distinction between form (no pun intended)
and function makes it possible to use a single form model on multiple platforms and devices, by
defining what the form is supposed to do once, and then further defining the user interface for each
device or platform to be supported separately.
XForms also come with built-in data typing capabilities and event handlers, making it possible to
validate user input without having to resort to complex scripting or server-side business logic.
XForms can even be integrated with the validation rules laid down in XML Schemas, to further
centralize application logic and reduce the impact of changes in business rules.
Another good thing about XForms, especially as we move to a more XML-centric world, is its native
support for the XML standard. Data entered into an XForm is usually submitted to the receiving
application in XML format. This simplifies integration with third-party tools (which are gradually
becoming XML-aware) and also reduces the need for complex data processing and manipulation
routines, as the submitted data can easily be parsed using standard SAX or DOM interfaces.
There's only one problem - while the theory is certainly exciting, practical implementation still
leaves a lot to be desired. The W3C's XForms site at http://www.w3.org/MarkUp/Forms/ lists a
number of different XForms implementations, but the technology has yet to make an appearance in
any popular browser; this makes it harder to test and research.
Of the different implementations available, the examples in this tutorial were tested with
FormsPlayer (http://www.formsplayer.com/), though you will also get good results with X-Smiles, a
Java browser (http://www.x-smiles.org/) and Novell's XForms (http://www.novell.com/xforms).
Expect to spend some time with the documentation for each of these implementations to get your
XForms development environment up and running (tip: I found FormsPlayer to be the simplest to
install, as it integrates directly with Internet Explorer 6.0)
What's In A Name?
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=224
2 of 9 4/22/2014 8:14 AM
Let's start with a simple example that demonstrates the functionality of XForms.
<html xmlns=" http://www.w3.org/1999/xhtml" ; xmlns:xforms=" http://www.w3.org/2002/xforms/cr"> ;<head>
<!-- define the form model --><xforms:model id="enter"> <xforms:instance> <user> <name /> </user> </xforms:instance></xforms:model>
<basefont face="Arial"></head>
<body><font size="+1">What's In A Name?</font><br /><br / >
<!-- define the form interface --><xforms:input id="txtname" model="enter" ref="/user /name"> <xforms:label>Name</xforms:label> <xforms:hint>Enter your name, then press TAB</xf orms:hint></xforms:input>
<br />
<!-- do something with the input -->Welcome to XForms, <xforms:output model="enter" ref ="/user/name" />
</body></html>
Let's look at this line by line.
The first basic rule when dealing with XForms is that they cannot exist as independent entities;
instead, they're designed to be integrated with XHTML (or other markup) documents. That's why the
XForm above is enclosed within a regular XHTML document, and why the XHTML namespace has
been referenced at the top.
<html xmlns=" http://www.w3.org/1999/xhtml" ; xmlns:xforms=" http://www.w3.org/2002/xforms/cr"> ;...</html>
Note that in addition to the XHTML namespace, when dealing with XForms, you'll also need to
specify the XForms namespace, which is currently "http://www.w3.org/2002/xforms/cr";.
<!-- define the form model --><xforms:model id="enter">...</xforms:model>
The second basic rule when working with XForms is this: every XForm consists of two primary
components, a form model (which specifies functionality) and one or more form controls (which
handles presentation).
The form model, indicated by the <xforms:model> element, defines what the form does. This model
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=224
3 of 9 4/22/2014 8:14 AM
defines the data to be captured/modified by the form as well as the logical components that govern
how the form behaves on user interaction (including where the form should be submitted and how
to handle the various form events). The model also includes information on the bindings between
the form controls and the instance data, and can optionally link to external XML Schemas for
validation purposes.
The <xforms:model> element is usually accompanied with an "id" attribute, which contains a name
for the model; this name is used by the form controls in order to link the interface section of the
form to the correct form model. Obviously, this also means that you can have multiple models with
a single XHTML file, and link to each one by its name. Additionally, since the form model only
defines how the form works and has nothing to do with its presentation, it can easily be reused,
either within the same application or in other applications or platforms.
Typically, the <xforms:model> element appears within the <head> of the document, and encloses
an <xforms:instance> element.
<!-- define the form model --><xforms:model id="enter"> <xforms:instance> <user> <name /> </user> </xforms:instance></xforms:model>
The <xforms:instance> element defines the "instance data" for the form. This instance data is an
XML tree representation of the values associated with the form, and it can be defined inline (as
above) or imported from an external XML file. In this case, the XML structure is pretty simple - a
single root element called <user> encompassing one child element called <name>.
Normally, the <xforms:model> element would also contain information on where the form is to be
submitted via the <xforms:submission> element, data bindings via the <xforms:bind> element and
event handlers via the <xforms:action> element - I'll be discussing those shortly, so don't worry too
much about them for the moment.
Once the form model has been defined, it's time to define the other half of the puzzle - the form
controls, or how the form looks. XForms provides a bunch of elements to accomplish this - by and
large, they map neatly into the HTML form controls you're already familiar with, and appear within
the <body> of the document.
<!-- define the form interface --><xforms:input id="txtname" model="enter" ref="/user /name"> <xforms:label>Name</xforms:label> <xforms:hint>Enter your name, then press TAB</xf orms:hint></xforms:input>
The first (and simplest) of these controls is the <xforms:input> element, which represents a text
entry field. Note my use of the "model" attribute to tell the XForms processor which form model this
control belongs to, and the "ref" attribute to tell it which node in the instance data tree this
particular value maps to. XPath expressions are used in the latter - in case you don't know what
those are, take a look at http://www.melonfire.com/community/columns/trog/article.php?id=83 and
they should make a little more sense to you.
<!-- do something with the input -->Welcome to XForms, <xforms:output model="enter" ref ="/user/name" />
Another useful (though not often used) form control is the <xforms:output> element, which is used
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=224
4 of 9 4/22/2014 8:14 AM
to display the value of a particular node from the XML instance data tree. Note again my usage of
the "model" and "ref" attributes to link the control to the model and instance data tree defined in
the <head> of the document.
If you were to try viewing the XForm above in an XForms-capable browser, you'd see something like
this:
Pretty cool, huh?
Welcome To Nowhere
The previous example demonstrated two of the form controls available in XForms. However, there
are lots more - here's a brief list:
<xforms:input> a single-line text entry field
<xforms:secret> a single-line text entry field which masks user input, good forpasswords
<xforms:select> a list field allowing multiple selection
<xforms:select1> a list field allowing selection of only a single item from thelist
<xforms:textarea> a multi-line text entry field
<xforms:upload> a file upload field
<xforms:range> a field which restricts entry t o a range of values
<xforms:submit> a form submission field
<xforms:output> a field for displaying values f rom the instance data
In addition, the XForms specification also defines the following elements, which may be attached to
the controls above:
<xforms:label> descriptive information for the corresponding control
<xforms:help> help information for the corres ponding control
<xforms:hint> brief usage information for the corresponding control
Here's an example demonstrating some of them in action:
<html xmlns=" http://www.w3.org/1999/xhtml" ; xmlns:xforms=" http://www.w3.org/2002/xforms/cr"> ;
<head>
<!-- form model --><xforms:model id="immigration"> <xforms:instance src="immigration.xml" />
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=224
5 of 9 4/22/2014 8:14 AM
</xforms:model><basefont face="Arial">
</head>
<body>
<!-- define interface controls --><table cellspacing="5" cellpadding="5" border="0"><tr><td colspan="2" align="center"><font color="red" si ze="4">Welcome toImmigration</font></td></tr>
<tr><td> <xforms:input id="txtname" model="immigration" r ef="/immigrant/name"> <xforms:label>Name</xforms:label> <xforms:hint>Enter your name here</xforms:hin t> </xforms:input></td></tr>
<tr><td> <xforms:input id="txtcitizenship" model="immigra tion" ref="/immigrant/citizenship"> <xforms:label>Citizenship</xforms:label> <xforms:hint>Enter your country of origin her e</xforms:hint> </xforms:input></td>
</tr><tr><td align="left"> <xforms:select1 model="immigration" ref="/immigr ant/purpose" appearance="full"> <xforms:label>Purpose of visit</xforms:label> <xforms:hint>Please state the purpose of your visit</xforms:hint> <xforms:item> <xforms:label>Business</xforms:label> <xforms:value>B</xforms:value> </xforms:item> <xforms:item> <xforms:label>Pleasure</xforms:label> <xforms:value>P</xforms:value> </xforms:item> <xforms:item> <xforms:label>Other</xforms:label> <xforms:value>O</xforms:value> </xforms:item> </xforms:select1></td></tr>
<tr><td align="left"> <xforms:select model="immigration" ref="/immigra nt/immunization"appearance="full"> <xforms:label>Immunization</xforms:label> <xforms:hint>Please select the diseases that you have been immunizedagainst</xforms:hint> <xforms:item> <xforms:label>Smallpox</xforms:label> <xforms:value>100</xforms:value> </xforms:item> <xforms:item> <xforms:label>Malaria</xforms:label> <xforms:value>113</xforms:value> </xforms:item>
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=224
6 of 9 4/22/2014 8:14 AM
<xforms:item> <xforms:label>Yellow fever</xforms:label> <xforms:value>56</xforms:value> </xforms:item> <xforms:item> <xforms:label>Typhoid</xforms:label> <xforms:value>174</xforms:value> </xforms:item> </xforms:select></tr>
<tr><td align="left"> <xforms:textarea model="immigration" ref="/immig rant/address"> <xforms:label>Address in home country</xforms :label> </xforms:textarea></td></tr></table>
</body></html>
First up, the definition of the XForms model. Unlike the previous example, I've defined the instance
data tree in a separate file and imported it via the "src" attribute.
<!-- form model --><xforms:model id="immigration"> <xforms:instance src="immigration.xml" /></xforms:model><basefont face="Arial">
Here's what "immigration.xml" looks like:
<?xml version="1.0" encoding="iso-8859-1"?><!-- immigration.xml --><immigrant> <name /> <citizenship /> <purpose /> <immunization /> <address /></immigrant>
You've already seen how to use an <xforms:input> element in previous examples, so I won't go into
the details again. Do note, however, my usage of the <xforms:label> and <xforms:hint> elements
within it - these come in handy to provide descriptive human-readable information about the
control.
<xforms:input id="txtname" model="immigration" r ef="/immigrant/name"> <xforms:label>Name</xforms:label> <xforms:hint>Enter your name here</xforms:hin t> </xforms:input>
The <xforms:select1> element allows the user to select one item from a series of options:
<xforms:select1 model="immigration" ref="/immigr ant/purpose" appearance="full"> <xforms:label>Purpose of visit</xforms:label> <xforms:hint>Please state the purpose of your visit</xforms:hint>
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=224
7 of 9 4/22/2014 8:14 AM
<xforms:item> <xforms:label>Business</xforms:label> <xforms:value>B</xforms:value> </xforms:item> <xforms:item> <xforms:label>Pleasure</xforms:label> <xforms:value>P</xforms:value> </xforms:item> <xforms:item> <xforms:label>Other</xforms:label> <xforms:value>O</xforms:value> </xforms:item> </xforms:select1>
Within the <xforms:select1> element, the list of available choices are defined via one or more
<xforms:item> elements, each of which must have a label and value; the former is displayed to the
user and the latter is passed to the server on submission.
A special "appearance" attribute in the <xforms:select1> element can be used to control the display
of the element in the browser ("full" for a list of all values, "minimal" for a minimum number of
values, and "compact" for a scrollable list).
Similar, though not identical to the above, is the <xforms:select> element, which allows the user to
select more than one value from the options available.
<xforms:select model="immigration" ref="/immigra nt/immunization"appearance="full"> <xforms:label>Immunization</xforms:label> <xforms:hint>Please select the diseases that you have been immunizedagainst</xforms:hint> <xforms:item> <xforms:label>Smallpox</xforms:label> <xforms:value>100</xforms:value> </xforms:item> <xforms:item> <xforms:label>Malaria</xforms:label> <xforms:value>113</xforms:value> </xforms:item> <xforms:item> <xforms:label>Yellow fever</xforms:label> <xforms:value>56</xforms:value> </xforms:item> <xforms:item> <xforms:label>Typhoid</xforms:label> <xforms:value>174</xforms:value> </xforms:item> </xforms:select>
As before, the choices are defined via a series of <xforms:label> and <xforms:value> elements,
while the "appearance" attribute can be used to control the appearance of the control ("full" for a
list of all values, "minimal" for a minimum number of values, and "compact" for a scrollable list).
Finally, the <xforms:textarea> element is used to display a multi-line text entry box, suitable for
use with large blocks of text.
<xforms:textarea model="immigration" ref="/immig rant/address"> <xforms:label>Address in home country</xforms :label> </xforms:textarea>
And here's what it all looks like:
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=224
8 of 9 4/22/2014 8:14 AM
Now, all this is fine and dandy - but how about submitting the form and actually doing something
with the user's data?
Well, that's a whole new kettle of fish, one which involves jumping through a complicated series of
hoops involving the <xsd:submission> element. I don't plan to discuss it now - instead, I'm going to
defer it to the second segment of this tutorial and instead encourage you to spend the interim
playing with the various form controls to understand how they work. Each control comes with
specific properties that can be used to customize its behaviour - so take a look at the specification,
get comfortable with them, try out a couple of implemetations, and come back next week to take
the next step in our XForms journey!
Note: Examples are illustrative only, and are not meant for a production environment. Melonfire
provides no warranties or support for the source code described in this article. YMMV!
Copyright notice:
This article is copyright Melonfire, 2014. All rights reserved.
All source code, brand names, trademarks and other content contained herein and proprietary to
Melonfire, 2014. All rights reserved.
Source code within this article is provided with NO WARRANTY WHATSOEVER. It is meant for
illustrative purposes only, and is NOT recommended for use in production environments.
Copyright infringement is a violation of law.
Printed from http://www.melonfire.com/community/columns/trog/article.php?id=224
Copyright © 1998-2014 Melonfire. All rights reservedTerms and Conditions | Feedback
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=224
9 of 9 4/22/2014 8:14 AM
Community
Trog
Copyright notice:
This article is copyright Melonfire, 2014. All rights reserved.
All source code, brand names, trademarks and other content contained herein is proprietary to
Melonfire, 2014. All rights reserved.
Source code within this article is provided with NO WARRANTY WHATSOEVER. It is meant for
illustrative purposes only, and is NOT recommended for use in production environments.
Copyright infringement is a violation of law.
Printed from http://www.melonfire.com/community/columns/trog/article.php?id=226
XForms Basics (part 2)Find out how to submit XForms data to a server-side script or save it to a local client file.
Revving Up
In the first part of this series, I gave you a quick introduction to the newly-released XForms 1.0
specification, by explaining the fundamental concepts of the XForms model. I showed you how to
define an XForms model and form instance data, as well as the logical components that govern how
the form behaves on user interaction. I also took you on a whirlwind tour of the various input
controls available in XForms 1.0 - as you will have seen, these controls correspond closely with the
controls available in traditional HTML, and then some.
Now, all this is fine and dandy - but how about submitting the form and actually doing something
with the user's data? Well, that's where this article comes in. Over the next few pages, I'm going to
answer this vexing question, showing you how to handle form submissions on both the server and
the client. XForms offers the creative developer an immense amount of control over the process,
primarily by doing away with the traditional name=value submission format in favour of standard
XML markup for user data.
I won't just stop there, though. Once you've understood how to store user data on the server with
XForms, I'll show you how to control the quality of that data by having XForms validate user input
at the time of submission. As you'll see, XForms' built-in support for data validation means you don't
need JavaScript or server-side logic any more. Instead, you can quality-control user input through
built-in XForms constructs or - if you want to get really advanced - hook your XForms up to an XML
Schema to enforce more sophisticated validation and typing rules.
Excited? I hope so.
Welcome To Immigration
I'll begin with a simple XForm, one that you're already familiar with from the previous segment of
this tutorial:
<html xmlns=" http://www.w3.org/1999/xhtml" ; xmlns:xforms=" http://www.w3.org/2002/xforms/cr"> ;
<head>
<!-- form model --><xforms:model id="immigration">
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=226
1 of 12 4/22/2014 8:13 AM
<xforms:instance src="immigration.xml" /> <xforms:submission id="submit" action="/tmp/immi grant.xml" method="put" /></xforms:model><basefont face="Arial">
</head>
<body>
<!-- define interface controls --><table cellspacing="5" cellpadding="5" border="0"><tr><td colspan="2" align="center"><font color="red" si ze="4">Welcome toImmigration</font></td></tr>
<tr><td> <xforms:input id="txtname" model="immigration" r ef="/immigrant/name"> <xforms:label>Name</xforms:label> <xforms:hint>Enter your name here</xforms:hin t> </xforms:input></td></tr>
<tr><td> <xforms:input id="txtcitizenship" model="immigra tion" ref="/immigrant/citizenship"> <xforms:label>Citizenship</xforms:label> <xforms:hint>Enter your country of origin her e</xforms:hint> </xforms:input></td>
</tr><tr><td align="left"> <xforms:select1 model="immigration" ref="/immigr ant/purpose" appearance="full"> <xforms:label>Purpose of visit</xforms:label> <xforms:hint>Please state the purpose of your visit</xforms:hint> <xforms:item> <xforms:label>Business</xforms:label> <xforms:value>B</xforms:value> </xforms:item> <xforms:item> <xforms:label>Pleasure</xforms:label> <xforms:value>P</xforms:value> </xforms:item> <xforms:item> <xforms:label>Other</xforms:label> <xforms:value>O</xforms:value> </xforms:item> </xforms:select1></td></tr>
<tr><td align="left"> <xforms:select model="immigration" ref="/immigra nt/immunization"appearance="full"> <xforms:label>Immunization</xforms:label> <xforms:hint>Please select the diseases that you have been immunizedagainst</xforms:hint> <xforms:item> <xforms:label>Smallpox</xforms:label> <xforms:value>100</xforms:value> </xforms:item> <xforms:item> <xforms:label>Malaria</xforms:label>
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=226
2 of 12 4/22/2014 8:13 AM
<xforms:value>113</xforms:value> </xforms:item> <xforms:item> <xforms:label>Yellow fever</xforms:label> <xforms:value>56</xforms:value> </xforms:item> <xforms:item> <xforms:label>Typhoid</xforms:label> <xforms:value>174</xforms:value> </xforms:item> </xforms:select></tr>
<tr><td align="left"> <xforms:textarea model="immigration" ref="/immig rant/address"> <xforms:label>Address in home country</xforms :label> </xforms:textarea></td></tr></table>
<xforms:submit submission="submit"> <xforms:label>Save</xforms:label> <xforms:hint>Save the information entered above to a local file</xforms:hint></xforms:submit>
</body></html>
Looks familiar? It should - this is the same form I used to demonstrate the various input controls
earlier, with one important addition: the ability to actually do something with the data once it has
been entered by the user.
The XForms specification defines an <xforms:submission> element, that specifies how form
submission is to be handled. Typically, this element appears in the <head> of the document, within
an <xforms:model> element, and contains information on the URL to which the form is to be
submitted, the method of submission, and the format and structure of the submitted XML. Here's an
example:
<xforms:submission id="submit" action="/tmp/immigra nt.xml" method="put" />
This is similar to the data that appears in the standard HTML <form> tag. Note the addition of an
"id" element - this is used to link the <xforms:submission> element with the actual form submit
button - and the method used (PUT, because in this first example, I'll be writing the form data to a
local file, not a server storage engine).
The <xforms:submission> element is only part of the puzzle. The other half is the submit button
itself, represented by the <xforms:submit> input control (remember this from last time's lesson?).
Here's what it looks like:
<xforms:submit submission="submit"> <xforms:label>Save</xforms:label> <xforms:hint>Save the information entered above to a local file</xforms:hint></xforms:submit>
Pretty standard, this - like other input controls, it contains optional <xforms:label> and
<xforms:hint> elements to give the user additional information on what it's supposed to do. The
novel thing here, though, is the additional "submission" attribute, which associates this submit
button with the <xforms:submission> element defined in the XForms model. Because of this link,
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=226
3 of 12 4/22/2014 8:13 AM
the <xforms:submit> element will trigger the "action" specified in the <xforms:submission>
element when invoked.
Now, let's give it a whirl to see it if works as advertised. Enter some data into the form and hit the
"Save" button. Then, navigate to the location specified in the "action" attribute and open up the
target file in a text editor. You should see the data you entered, formatted in XML as per your form
model. Here's an example:
<!-- immigration.xml--><immigrant><name>Chewbacca</name><citizenship>Tatoo ine</citizenship><purpose>B</purpose><immunization>56 113 100</immun ization><address>PlanetTatooine</address></immigrant>
Behind the scenes, here's what happens when the form is submitted:
1. An "xforms-submit" event is triggered (more on events shortly).
2. The instance data tree beginning at the root specified in the <xforms:submission> element is
selected. If no root is specified (as in the example above), the entire instance data tree is selected.
3. The selected instance data is validated as per validation rules that may be specified in the XForm.
If an error occurs in validation, processing stops and an exception is generated.
4. If the data passes all the validation tests, it is serialized and submitted using the information
provided in the "method" and "action" attributes of the <xforms:submission> element.
Data Overload
The previous example showed you how to store the information provided by the user in a local file
on the client. Though this seems interesting at first glance, it isn't very useful in real life (when was
the last time you wanted to do this?) Most often, you would want the data to be sent to the server,
safe and secure in a database or other storage engine. How does XForms stand up to this challenge?
Pretty well, actually - and it even adds some interesting attributes to control the data being
submitted.
In order to demonstrate, I'll revise the previous example to submit the user data to a server-side
script, which takes care of adding it to a MySQL database. In this example, the database is called
"db1", the table is called "immigrants", and the SQL code to create the table looks like this:
CREATE TABLE `immigrants` ( `id` int(11) NOT NULL auto_increment, `name` varchar(30) NOT NULL default '', `citizenship` varchar(50) NOT NULL default '', `purpose` char(1) NOT NULL default '', `immunization` varchar(50) NOT NULL default '', `address` varchar(255) NOT NULL default '', PRIMARY KEY (`id`))
As you can see, this is pretty straightforward stuff, with each field of the table mapping to a node in
the XML file created in the previous example.
Next up, altering the XForm model to point to a server-side PHP script instead of a local file:
<!-- form model --><xforms:model id="immigration"> <xforms:instance src="immigration.xml" /> <xforms:submission id="submit" action="/scripts/ register.php" method="post" />
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=226
4 of 12 4/22/2014 8:13 AM
</xforms:model>
Notice that no change is needed to the form input controls, or any other section of the XForm - this
is an example of the separation between form and function that XForms promises.
Finally, here's the PHP script that takes the submitted form data and converts it into an INSERT
query:
<?php
// initialize some variables;$currentTag = "";$values = array();$allowedFields = array("name", "citizenship", "purp ose", "immunization", "address");
// database parameters$host = "localhost";$usr = "john";$pwd = "doe";$db = "db1";
// handlersfunction startElementHandler($parser, $name, $attri butes){ global $currentTag; $currentTag = $name;}
function endElementHandler($parser, $name){ global $values, $currentTag; global $connection, $table; if(strtolower($name) == "immigrant") { // generate SQL $query = "INSERT INTO immigrants"; $query .= "(name, citizenship, purpose, immun ization, address)"; $query .= "VALUES(\"" . join("\",\"",$values) . "\");"; // uncomment for debug purposes // print $query; // execute query $result = mysql_query($query) or die("Error i n query: $query. " .mysql_error()); // reset variables $values = array(); $currentTag = ""; }}
function characterDataHandler($parser, $data){ global $currentTag, $values, $allowedFields; $currentTag = strtolower($currentTag); if(in_array($currentTag, $allowedFields) && trim ($data) != "") { $values[$currentTag] = mysql_escape_string($d ata); } }
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=226
5 of 12 4/22/2014 8:13 AM
$parser = xml_parser_create();
// get the XML data$data = $HTTP_RAW_POST_DATA;
// set SAX parser optionsxml_parser_set_option($parser,XML_OPTION_CASE_FOLDI NG,0);xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE ,1);
// set element handlersxml_set_element_handler($parser, "startElementHandl er", "endElementHandler");xml_set_character_data_handler($parser, "characterD ataHandler");
// connect to database$conn = mysql_connect($host, $usr, $pwd) or die("Un able to connect to the database");mysql_select_db($db) or die("Unable to select datab ase");
// parse XMLif (!xml_parse($parser, $data )){ die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser)));}
// clean upxml_parser_free($parser);mysql_close();
?>
Now try it out and see for yourself - enter some data into the form, submit it and then check the
database to see if your values were inserted correctly. Here's what you might see:
mysql> SELECT * FROM immigrants;+----+-----------+-------------+---------+--------- -----+-----------------+| id | name | citizenship | purpose | immuniza tion | address |+----+-----------+-------------+---------+--------- -----+-----------------+| 1 | Chewbacca | Tatooine | B | 56 113 | Planet Tatooine |+----+-----------+-------------+---------+--------- -----+-----------------+1 row in set (0.00 sec)
How did this happen? Well, unlike traditional forms, which submit data using name-value pairs,
XForms submits data as a well-formed XML document. This document can then be parsed using
either a DOM or SAX parser, or even transferred directly to any other application that understands
XML.
PHP comes with a built-in SAX parser, which is what I've used in the example above to parse the
XML document. SAX, or the Simple API for XML, is one of the most common methods of parsing an
XML document. Essentially, a SAX parser reads the XML document sequentially, triggering specific
user-defined functions when it finds an opening tag, character data, closing tag, CDATA block and so
on. In the example above, these user-defined functions are called startElementHandler(),
endElementHandler() and characterDataHandler().
$parser = xml_parser_create();xml_set_element_handler($parser, "startElementHandl er", "endElementHandler");xml_set_character_data_handler($parser, "characterD ataHandler");
Of these, the major work in the script above is done by the characterDataHandler() function - this
reads the various values entered by the user from the XML document tree and builds the SQL query
after using the mysql_escape_string() function to make the values ready for insertion in the
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=226
6 of 12 4/22/2014 8:13 AM
database.
function characterDataHandler($parser, $data){ global $currentTag, $values, $allowedFields; $currentTag = strtolower($currentTag); if(in_array($currentTag, $allowedFields) && trim ($data) != "") { $values[$currentTag] = mysql_escape_string($d ata); } }
The script above won't make much sense to you unless you've played a little with SAX. In case you
haven't, drop by http://www.melonfire.com/community/columns/trog/article.php?id=71 and find out
what you missed, then come back here and review the script again. You can also read more about
SAX at http://www.saxproject.org/ and http://www.xmlphp.com/
You can also parse the XML document submitted by the XForm using the DOM - I leave that to you
as an exercise.
A Custom Job
In addition to the attributes you've already seen, the <xforms:submission> element also comes with
a bunch of others, which can assist in customizing the manner in which the form data is submitted.
Here's a brief list:
"ref" - specifies the node to use as root when submitting instance data, defaults to /
"version" - specifies XML version to use when submitting form data
"indent" - toggles indenting of XML data in form submission
"encoding" - specifies XML encoding to use when submitting form data
"omit-xml-declaration" - toggles XML declaration when submitting form data
"standalone " - toggles standalone declaration when submitting form data
"replace" - specifies what to do with the response to the submission
Consider the following example, which demonstrates some of these in action:
<html xmlns=" http://www.w3.org/1999/xhtml" ; xmlns:xforms=" http://www.w3.org/2002/xforms/cr"> ;
<head>
<!-- form model --><xforms:model id="information"> <xforms:instance> <user> <name /> <email /> <age /> </user> </xforms:instance> <xforms:submission id="submit" ref="/user/name" action="/tmp/user.xml"method="put" indent="yes" omit-xml-declaration="no" />
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=226
7 of 12 4/22/2014 8:13 AM
</xforms:model><basefont face="Arial">
</head>
<body>
<!-- define interface controls --><table cellspacing="5" cellpadding="5" border="0"><tr><td> <xforms:input id="txtname" model="information" r ef="/user/name"> <xforms:label>Name</xforms:label> <xforms:hint>Enter your name here</xforms:hin t> </xforms:input></td></tr>
<tr><td> <xforms:input id="txtemail" model="information" ref="/user/email"> <xforms:label>Email address</xforms:label> <xforms:hint>Enter your email address here</x forms:hint> </xforms:input></td>
<td> <xforms:input id="txtage" model="information" re f="/user/age"> <xforms:label>Age</xforms:label> <xforms:hint>Enter your age here</xforms:hint > </xforms:input></td>
</table>
<xforms:submit submission="submit"> <xforms:label>Save</xforms:label> <xforms:hint>Save the information entered above to a local file</xforms:hint></xforms:submit>
</body></html>
In this case, I've explicitly told the XForms processor to include the XML declaration in the final form
submission, but to only include that part of the instance data tree beginning with the element
<name>. Here's the output:
<?xml version="1.0" encoding="ISO-8859-1"?><name>Ha rish</name>
It's important to note, also, that XForms supports submitting data in more than just PUT and POST
methods, and that if you really need to, you can even replicate the behaviour of traditional HTML
forms by submitting your data in the standard name=value format. The method atribute of the
<xforms:submission> element can take any of the values "post", "get", "put", "multipart-post" and
"form-data-post" - take a look at the specification to see what each one of these does.
Not My Type
Speak to any Web developer, and they're sure to complain about the need to write complex
JavaScript code to carry out elementary data validation on form input. With XForms, they are no
longer hostage to JavaScript - XForms is closely integrated with XML Schema, and can use XML
Schema datatypes to perform both simple and complex form validation. Take a look at the next
example, which illustrates:
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=226
8 of 12 4/22/2014 8:13 AM
<html xmlns=" http://www.w3.org/1999/xhtml" ; xmlns:xforms=" http://www.w3.org/2002/xforms/cr"> ;<head>
<!-- define the form model --><xforms:model id="enter"> <xforms:instance> <user xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" ; xmlns:xsd=" http://www.w3.org/2001/XMLSchema"> ; <name xsi:type="xsd:string" /> <age xsi:type="xsd:integer" /> <dob xsi:type="xsd:date" /> <height xsi:type="xsd:float" /> <weight xsi:type="xsd:decimal" /> <immunizaton xsi:type="xsd:boolean" /> </user> </xforms:instance></xforms:model>
<basefont face="Arial">
</head>
<body>
<font size="+1">So you wanna join The Army?</font>< br /><br />
<!-- form controls --><xforms:input id="txtname" model="enter" ref="/user /name"> <xforms:label>Name</xforms:label> <xforms:hint>Enter your name</xforms:hint> <xforms:alert>Haven't you got a name, mate?</xfo rms:alert></xforms:input>
<xforms:input id="txtage" model="enter" ref="/user/ age"> <xforms:label>Age</xforms:label> <xforms:hint>Enter your age in years</xforms:hin t> <xforms:alert>Can't you read? Tell me your age!< /xforms:alert></xforms:input>
<xforms:input id="txtdob" model="enter" ref="/user/ dob"> <xforms:label>Date of birth</xforms:label> <xforms:hint>Enter your date of birth</xforms:hi nt> <xforms:alert>You can forget your birthday gift, brother!</xforms:alert></xforms:input>
<xforms:input id="txtheight" model="enter" ref="/us er/height"> <xforms:label>Height</xforms:label> <xforms:hint>Enter your height in feet and inche s</xforms:hint> <xforms:alert>Don't have a measuring tape, do yo u?</xforms:alert></xforms:input>
<xforms:input id="txtweight " model="enter" ref="/u ser/weight"> <xforms:label>Weight</xforms:label> <xforms:hint>Enter your weight in pounds</xforms :hint> <xforms:alert>Come on fatso, 'fess up!</xforms:a lert></xforms:input>
<xforms:input id="boolimmunization" model="enter" r ef="/user/immunization"> <xforms:label>Have you been immunized against ma jor diseases?</xforms:label> <xforms:hint>Enter your immunization status</xfo rms:hint> <xforms:alert>Don't lie, we have syringes with l arge needles!</xforms:alert></xforms:input>
</body></html>
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=226
9 of 12 4/22/2014 8:13 AM
At first glance, the above example looks much like the examples we have discussed so far. But a
closer inspection of the model reveals a subtle difference...
<xforms:model id="enter"> <xforms:instance> <user xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" ; xmlns:xsd=" http://www.w3.org/2001/XMLSchema"> ; <name xsi:type="xsd:string" /> <age xsi:type="xsd:integer" /> <dob xsi:type="xsd:date" /> <height xsi:type="xsd:float" /> <weight xsi:type="xsd:decimal" /> <immunizaton xsi:type="xsd:boolean" /> </user> </xforms:instance></xforms:model>
For starters, I have two new namespaces, one for XML Schema and the second for the XML Schema
instance. Both these are required for the new features that I'm going to introduce in this example.
Next, take a closer look at the definition of the XForms model. You'll see that each element contains
a new "xsi:type" attribute. This attribute, which references datatypes from the XML Schema
namespace (hence the "xsd:" namespace identifier) makes it possible to easily use those datatypes
within XForms. Once datatypes have been defined in this manner, and links to the form controls
have been set up via "ref" attributes, the XForms processor will generate an error if the data
entered into a field does not match the datatype associated with it in the form model.
How is this error handled? Simple - with the new <xforms:alert> element, which can be used to
display control-specific errors or alerts. Take a look at this snippet, which illustrates:
<xforms:input id="txtage" model="enter" ref="/user/ age"> <xforms:label>Age</xforms:label> <xforms:hint>Enter your age in years</xforms:hin t> <xforms:alert>Can't you read? Tell me your age!< /xforms:alert></xforms:input>
Here, if the user does not enter data consistent with the definition for the control, the message
specified in the <xforms:alert> field will be displayed.
The Number Game
If you have special needs, you can even create your own datatypes using XML Schema, instead of
restricting yourself to the pre-defined datatypes. Consider the following example, which illustrates:
<html xmlns=" http://www.w3.org/1999/xhtml" ; xmlns:xforms=" http://www.w3.org/2002/xforms/cr"> ;
<head>
<!-- form model --><xforms:model id="information" schema="users.xsd"> <xforms:instance> <user> <name xsi:type="xsd:string" /> <email xsi:type="xsd:string" /> <age xsi:type="adultsOnly" /> </user> </xforms:instance> <xforms:submission id="submit" ref="/user/name" action="/scripts/save.cgi"method="post" indent="yes" omit-xml-declaration="no " />
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=226
10 of 12 4/22/2014 8:13 AM
</xforms:model>
<basefont face="Arial">
</head>
<body>
<!-- define interface controls --><table cellspacing="5" cellpadding="5" border="0"><tr><td> <xforms:input id="txtname" model="information" r ef="/user/name"> <xforms:label>Name</xforms:label> <xforms:hint>Enter your name here</xforms:hin t> </xforms:input></td></tr>
<tr><td> <xforms:input id="txtemail" model="information" ref="/user/email"> <xforms:label>Email address</xforms:label> <xforms:hint>Enter your email address here</x forms:hint> </xforms:input></td>
<td> <xforms:input id="intage" model="information" re f="/user/age"> <xforms:label>Age</xforms:label> <xforms:hint>Enter your age here</xforms:hint > </xforms:input></td>
</table>
<xforms:submit submission="submit"> <xforms:label>Save</xforms:label></xforms:submit>
</body></html>
You'll notice that I've defined a custom type in the form model - something called "adultsOnly". The
definition for this type is stored in an XML Schema, and it only allows you to enter values equal to
or over 18 into the corresponding field. Take a look:
<?xml version="1.0" encoding="UTF-8"?><xsd:schema xmlns:xsd=" http://www.w3.org/2001/XMLSchema"> ; <xsd:simpleType name="adultsOnly"> <xsd:restriction base="xsd:integer"> <xsd:minInclusive value="18" /> </xsd:restriction></xsd:simpleType></xsd:schema>
And that's about it for today. In this article, I began by discussing the XForms submission process,
and explained how to use the <xforms:submission> element to save form input to a local file with
the PUT method, and how to pass it to a server-side script for storage in a MySQL database. I also
showed you a real-world example of the latter, by using the PHP SAX parser to parse the instance
document generated by an XForms submission and convert it into an SQL query string.
Next, I taught you how XForms significantly simplifies the task of input validation, by integrating
with XML Schema datatypes and allowing you to validate user input against those datatypes. Here
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=226
11 of 12 4/22/2014 8:13 AM
too, I showed you a couple of different examples, one using XML Schema built-in datatypes and the
other using my own custom types.
Next week, I'll be delving a little deeper into the XForms specification, explaining binding, form
events, and built-in functions. Until then...stay healthy!
Note: Examples are illustrative only, and are not meant for a production environment. Melonfire
provides no warranties or support for the source code described in this article. YMMV!
Copyright notice:
This article is copyright Melonfire, 2014. All rights reserved.
All source code, brand names, trademarks and other content contained herein and proprietary to
Melonfire, 2014. All rights reserved.
Source code within this article is provided with NO WARRANTY WHATSOEVER. It is meant for
illustrative purposes only, and is NOT recommended for use in production environments.
Copyright infringement is a violation of law.
Printed from http://www.melonfire.com/community/columns/trog/article.php?id=226
Copyright © 1998-2014 Melonfire. All rights reservedTerms and Conditions | Feedback
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=226
12 of 12 4/22/2014 8:13 AM
Community
Trog
Copyright notice:
This article is copyright Melonfire, 2014. All rights reserved.
All source code, brand names, trademarks and other content contained herein is proprietary to
Melonfire, 2014. All rights reserved.
Source code within this article is provided with NO WARRANTY WHATSOEVER. It is meant for
illustrative purposes only, and is NOT recommended for use in production environments.
Copyright infringement is a violation of law.
Printed from http://www.melonfire.com/community/columns/trog/article.php?id=228
XForms Basics (part 3)Perform calculations on form input values and get a crash course in the XForms event
model.
Endgame
In the previous article, I showed you how to manage user input in the XForms model. I discussed
the process of submitting an XForm and - more importantly - validating user input prior to
submission using built-in XML Schema support.
In this concluding segment, I'll introduce you to some of XForms' more arcane features. First, the
concept of binding, which allows developers to implement a number of useful features quickly -
calculating values instantly, enforcing basic validation rules, taking decisions on the fly or rendering
a particular node non-writable.
Next, I'll briefly show you how you can use XPath functions within an XForms model definition, and
illustrate how functions like sum() and avg() allow you to perform complex calculations in a simple
and smooth manner. I'll also take a quick look at the XForms event processing model, explaining the
important phases and showing you a basic example of how triggers and actions work.
Let's get started, shall we?
Operating With Extreme Caution
You've already seen how various XML technologies integrate seamlessly with each other when it
comes to XForms. In fact, in the last part of this tutorial, I showed you how to re-use an XML
Schema datatype definition in an XForms model, and how to use XPath expressions to reference and
bind instance data with the XForms user interface. But why stop there? You can also use logical,
comparison and arithmetic operators and functions with XPath expressions, in order to perform
calculations using the instance data in an XForms model.
In order to do this, you need to first understand the <xforms:bind> element, which makes it
possible to bind instance data elements to specific properties and constraints. The <xforms:bind>
element comes with a number of additional attributes, which can be used to specify whether a
particular element of the instance data is required, read-only, constrained to specific values or
compliant with a specific type.
Consider the following example, which demonstrates:
<!-- form model -->
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=228
1 of 7 4/22/2014 8:14 AM
<xforms:model id="account"> <xforms:instance> <account> <name /> <number /> </account> </xforms:instance><xforms:bind id="accountNumberRequired" nodeset="/a ccount/number" required="true()"/></xforms:model>
In this case, the bind definition states that the account number is required in order for the form to
be submitted. This is a very fundamental example of input validation. With normal HTML forms,
you'd need to write client-side and server-side code to manage this requirement; with XForms, it
comes built-in!
In case you were wondering where this bind definition gets used, the XForms specification states
that user interface elements can then be linked to the definition, simply by adding a "bind" attribute
to the interface control (instead of the traditional "ref" attribute). Here's an example:
<!-- define the form interface --><xforms:input bind="accountNumberRequired"> <xforms:label>Account number</xforms:label></xforms:input>
Money, Money, Money
Of course, the "required" attribute is just one example of what XForms calls "model item
properties". Another one is the "relevant" attribute, which specifies when a particular element of the
instance data is enabled or disabled. Consider the following example, which illustrates:
<!-- form model --><xforms:model id="tran"> <xforms:instance> <transaction> <type /> <amount /> <checkNumber /> </transaction> </xforms:instance><xforms:bind nodeset="/transaction/checkNumber" rel evant="/transaction/type='check'"/></xforms:model>
Basically, this says that when performing a transaction (in this case, a bank account transaction
which is either a deposit or a withdrawal) the check number is only relevant when the transaction
involves a check.
Of course, it's up to the implementation to decide how to handle this particular property. Some
implementations might disable the field for data entry during cash transactions, others might hide
it, and still others might pop up a warning.
You'll notice, also, that the "relevant" property contains an equality test. Model item properties can
contain comparison tests, so long as these conform to the rules laid down for XPath expressions.
Here's another example, this one illustrating the use of a comparison test with the previously-
explained "required" property by requiring the entry of a tax identification number for transactions
greater than $50,000:
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=228
2 of 7 4/22/2014 8:14 AM
<!-- form model --><xforms:model id="taxes"> <xforms:instance> <transaction> <name /> <amount /> <taxID /> </transaction> </xforms:instance><xforms:bind id="taxIDRequired" nodeset="/transacti on/taxID" required="/transaction/amount > 50000" /></xforms:model>
Shop Till You Drop
It's also possible to specify that a particular element of the instance data be read-only via the
"readonly" property. Consider the following example:
<!-- form model --><xforms:model id="shop"> <xforms:instance> <item> <code /> <price /> <discount>2.00</discount> <quantity /> <grossTotal /> <netTotal /> </item> </xforms:instance><xforms:bind nodeset="/item/discount" readonly="tru e()" /></xforms:model>
In this case, since you don't want users messing with the discount rate, you can use the "readonly"
property to make it non-modifiable. As before, you can combine this with comparison tests to make
the property's relevance conditional.
One extremely useful property in this context - and one you'll probably be using a lot - is the
"calculate" property, which lets you calculate some of the form data on the fly. Consider the
following extension of the example above, which illustrates:
<!-- form model --><xforms:model id="shop"> <xforms:instance> <item> <code /> <price /> <discount>2.00</discount> <quantity /> <grossTotal /> <netTotal /> </item> </xforms:instance><xforms:bind nodeset="/item/discount" readonly="tru e()" /><xforms:bind nodeset="/item/grossTotal" calculate=" /item/price * /item/quantity" /><xforms:bind nodeset="/item/netTotal" calculate="/i tem/grossTotal - ((item/grossTotal* /item/discount)/100)" /></xforms:model>
In this case, the "calculate" property has been used to dynamically calculate the value of the
<grossTotal> element from the values of the <price> and <quantity> elements. The <netTotal> is
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=228
3 of 7 4/22/2014 8:14 AM
then again calculated from the <grossTotal> by accounting for the <discount>.
In case you were wondering why I haven't used a "readonly" property for the two dynamically-
calculated values - I don't need to, since these values are automatically made read-only when a
"calculate" property is used on them.
The Bookworm Turns
In addition to simple comparison tests, you can also use XPath arithmetic and non-arithmetic
functions in an XForms model. Consider the following example, which illustrates:
<html xmlns=" http://www.w3.org/1999/xhtml" ; xmlns:xforms=" http://www.w3.org/2002/xforms/cr" ; xmlns:xsd=" http://www.w3.org/2001/XMLSchema"> ;<head><!-- define the form model --><xforms:model id="bookstore"> <xforms:instance> <inventory> <books> <title>Be Cool</title> <author>Elmore Leonard</author> <price>7.97</price> <quantity>150</quantity>
<title>Mystic River</title> <author>Dennis Lehane</author> <price>25.00</price> <quantity>86</quantity>
<title>Hit List</title> <author>Lawrence Block</author> <price>23.76</price> <quantity>26</quantity>
<title>Silent Joe</title> <author>T. Jefferson Parker</author> <price>24.99</price> <quantity>268</quantity>
<title>The Travel Detective</title> <author>Peter Greenberg</author> <price>34.87</price> <quantity>9</quantity> </books>
<totalInventory />
<mostExpensive />
<leastExpensive />
<averageCost /> </inventory> </xforms:instance> <xforms:bind nodeset="/inventory/books/totalInve ntory" calculate="sum(/inventory/books/quantity)" /> <xforms:bind nodeset="/inventory/books/mostExpen sive" calculate="max(/inventory/books/price)" /> <xforms:bind nodeset="/inventory/books/leastExpe nsive" calculate="min(/inventory/books/price)" /> <xforms:bind nodeset="/inventory/books/averagePr ice" calculate="avg(/inventory/books/price)" />
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=228
4 of 7 4/22/2014 8:14 AM
</xforms:model></head>
<body><!-- define the form interface --><!-- loop over the instance data --><xforms:repeat nodeset="/inventory/books"> <xforms:input id="txttitle" ref="title"> <xforms:label>Title</xforms:label> </xforms:input> <xforms:input id="txtauthor" ref="author"> <xforms:label>Author</xforms:label> </xforms:input> <xforms:input id="txtprice" ref="price"> <xforms:label>Price</xforms:label> </xforms:input> <xforms:input id="txtquantity" ref="quantity"> <xforms:label>Quantity</xforms:label> </xforms:input></xforms:repeat>
<!-- print calculated values -->Total inventory: <xforms:output ref="/inventory/boo ks/totalInventory" /> <br />
Price of most expensive book: <xforms:output ref="/ inventory/books/mostExpensive" /><br />
Price of least expensive book: <xforms:output ref=" /inventory/books/leastExpensive"/> <br />
Average price: <xforms:output ref="/inventory/books /averagePrice" />
</body></html>
As usual, all the action is centered around the definition of the XForms model. This time around, the
instance data has been populated with the inventory of the neighbourhood bookstore, and XPath
functions like sum(), min(), max() and avg() have been used to perform calculations on that data,
and assign the results of those calculations to specific summary elements in the instance data. This
data is then displayed in the form using the <xforms:output> element.
You'll also notice a new element in the form above - the <xforms:repeat> element. This element
gives XForms authors the ability to loop over a collection of nodes without having to resort to
complex "while" or "for" loops. In this example, the <xforms:repeat> element causes the XForms
processor to iterate over the <books> collection from the instance data, and display the values of
the title, author, price and quantity. The "nodeset" attribute specifies the node over which iteration
should take place, while the loop counter is handled internally by the processor. Looping will stop
once no further match is found for the "nodeset" criteria.
Why stop just at numeric functions, though? This next example uses the days-from-date() function
to calculate the number of days between an entered date and January 01 1970.
The XForms model will look something like this:
<!-- form model --><xforms:model id="dateCalculator"> <xforms:instance> <calc> <dt /> <numDays /> </calc> </xforms:instance><xforms:bind nodeset="/calc/numDays" calculate="day s-from-date(/calc/dt)" /></xforms:model>
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=228
5 of 7 4/22/2014 8:14 AM
Pretty straightforward, isn't it?
An Event To Remember
It was the introduction of events in client-side scripting languages like JavaScript and VBScript that
brought about the rise of the dynamic Web site. However, inconsistencies in implementation across
browsers meant that developers had to grapple with multiple lines of code to make Web sites cross-
browser compatible. XForms has put an end to this misery, at least so far as form events are
concerned.
The XForms 1.0 specification divides the process of event handling into four phases:
Initialization: This is the very first stage, wherein the XForms processor "wakes up" and begins
construction of the data model using the instance data provided. This is also the stage where all
relevant XML Schemas are loaded, and all form controls (with their associated bindings) are
initialized.
Interaction: Interaction events are fired as a result of action from the user - for example, keyboard
navigation to a new input control, mouse clicks, data entry or item selection. A number of different
events can occur in this phase, and each one has a default action associated with it.
Notification: Notification events don't usually have a default action associated with them; rather,
they're triggered as a result of a change in the form state, such as a form control receiving focus or
a button being clicked.
Error handling: These events occur due to errors in XForm processing, such as illegal binding
expressions or illegal XPath references. Errors may be either fatal or non-fatal, depending on their
severity.
OK, now enough of the theory. Let's look at a simple example:
<!-- define the form model --><xforms:model id="bankAccount"> <xforms:instance> <account> <openingBalance>10000</openingBalance> <withdrawal /> <closingBalance /> </account> </xforms:instance>
<xforms:bind id="nodeClosingBalance" nodeset="/a ccount/closingBalance" />
</xforms:model>
<!-- define the form interface --><xforms:input id="txtwithdraw" ref="/account/withdr awal"> <xforms:label>Amount to withdraw</xforms:label> <xforms:hint>Please enter the amount you wish to withdraw</xforms:hint></xforms:input>
<xforms:trigger><xforms:label>Calculate Closing Balance</xforms:lab el><xforms:setvalue ev:event="DOMActivate" bind="nodeC losingBalance" value="/account/openingBalance - /account/withdrawal" /></xforms:trigger>
By definition, the <xforms:trigger> element is the XForms counterpart of the regular HTML form
button. When clicked, it generates a DOMActivate event, which is a catch-all event type fired
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=228
6 of 7 4/22/2014 8:14 AM
whenever any event (pressing a button, selecting an option) occurs. The <xforms:setvalue>
element, which is used to set the value for a particular node after computing it from an XPath
expression, listens for this event and acts when it receives it. In this case, the action involves
subtracting the withdrawal amount from the opening balance to obtain a new closing balance.
A number of other event types are available in the XForms model - you've already seen one of the
other important ones, the xforms-submit event, in the previous segment of this tutorial. There are
too many to list here, so you should take a look at the specification (and the excellent examples
included within it), to better understand this topic.
Link Out
And that's about all I have for you. Over the course of this three-part tutorial, I introduced you to
the new XForms 1.0 specification, and showed you how to create a data model and bind its elements
to form input controls. I also explained the various XForms input controls, and showed you how they
map into the standard HTML form controls.
Next, I discussed the process of submitting an XForm, with a look at the <xforms:submission>
element and the "submit" input control. I also showed you how to perform primitive datatype
validation in an XForm using built-in XML Schema datatypes, and how to extend this to perform
more complex validation by integrating your own custom datatypes into the XForms model.
Finally, in this concluding part, I introducing the concept of binding using the <xforms:bind>
element, which allows you to disable or enable input controls, mark them as read-only, enforce
special constraints on your input controls, and even calculate values on the fly - tasks which earlier
required complex JavaScript, but are now as simple as combining XPath expressions. I also looked at
some XPath functions, and showed you how you can use them within your binding expressions for
greater flexibility in calculations. I wrapped things up with a brief introduction to the XForms event
model - this is a fairly complex topic, and one which requires in-depth understanding of the XML
Events specification as well, so if you'd like to learn more about it, be prepared to spend some time
on research (with the specification in hand).
I hope you enjoyed this article, and that it gave you sufficient grounding to get you started with
XForms. XForms is one of the more interesting emerging XML technologies, and you can expect to
see it grow more powerful in subsequent iterations. So go on - it's time to practice!
Note: Examples are illustrative only, and are not meant for a production environment. Melonfire
provides no warranties or support for the source code described in this article. YMMV!
Copyright notice:
This article is copyright Melonfire, 2014. All rights reserved.
All source code, brand names, trademarks and other content contained herein and proprietary to
Melonfire, 2014. All rights reserved.
Source code within this article is provided with NO WARRANTY WHATSOEVER. It is meant for
illustrative purposes only, and is NOT recommended for use in production environments.
Copyright infringement is a violation of law.
Printed from http://www.melonfire.com/community/columns/trog/article.php?id=228
Copyright © 1998-2014 Melonfire. All rights reservedTerms and Conditions | Feedback
The Melonfire Community - Trog http://www.melonfire.com/community/columns/trog/print.php?id=228
7 of 7 4/22/2014 8:14 AM