Monday, May 22, 2006

XForms tutorial part 4: Declarative Binding Logic

THIS POST IS SUPERSEDED BY A NEW SERIES OF ARTICLES ON XML TECHNOLOGIES AND XFORMS... READ MORE IN PART 5 OF THE XFORMS TUTORIAL...




Again, I found the limitations of using beta software for demonstrations in this tutorial. This time however, I decided not to wait for a more stable version of the Mozilla XForms plugin. Instead, I accept a little unstable behavior and a few bugs and promise to fix example code later when needed. The example in part 3 stopped working in the latest version of the XForms plugin. This is fixed when the final plugin is released. For now, I hope you'll understand the examples with a few shortcomings.

In part 3 you may have noticed this tutorial will never make it in the "XYZ for Dummies" series. I prefer to dive straight into the advanced concepts. Part 3 introduced grouping and repeating elements. By now, you should have a basic feeling of the XML oriented nature of XForms and the dynamic response of the user interface to changes in the source document.

In this part, part 4, dynamic behavior of XForms is pushed to the limits. This post demonstrates the use of the xf:bind element for declarative specification of business logic. We start using CSS style sheets to specify layout. Data sources are stored in separate XML files. Both the source document and the interface become bilingual. Resource bundles are used for translation, separating model and content and preventing duplication. Bindings are used for hiding irrelevant elements and constraining input values.

The more I work with XForms, the more I realize how complex they really are. Considering the fact that XForms are the replacement for classic HTML forms in XHTML 2, I have my doubts that XHTML 2 will ever replace HTML 4. I am curious whether companies like Macromedia will be able to offer easy and user friendly XForms editors in products like Dreamweaver. Nevertheless, I am convinced that software developers and professional web designers will appreciate the advantages of XHTML 2 and push XForms in major web sites just like AJAX is pushed right now. After all, AJAX is no easier than XForms but it is widely adopted to enhance rich user interfaces in many web sites.


The Eclipse Apogee XForms implementation

Another promising development is the adoption of XForms outside web browsers. I found a proposal for an XForms implementation in Eclipse, called Apogee. Eclipse is an IDE (integrated development environment) for Java developers. There is also a stripped version of Eclipse which serves as a platform for building Rich Client applications in Java using native GUI controls while remaining reasonably platform independent. The Eclipse GUI framework is called SWT. The Apogee project proposal intends to extend Eclipse RCP (rich client platform) with components like a calendar, rich text editors (Office, XHTML) and XML support (XSD, SOAP, XForms).

If this proposal is accepted by the Eclipse project, this means a great step forward in the development of client side business applications in Java. XForms provide major productivity improvements in the development of form based programs. An application providing both a rich client interface and a web based interface could use the same XForms document for both the web and the client. XML oriented interfaces are no longer limited to web based implementations. This could mean the end of one-on-one binding of GUI elements to database fields.

The current alpha implementation still lacks some key XForms concepts but looks promising. I hope the developers don't underestimate the effort required for a full and stable XForms implementation. But judging the quality of current official Eclipse subprojects, Apogee might become one of the best implementations available. If you're interested, take a look at the project page. For testing the first milestone, you need to connect to the Subversion code repository and compile the plugins yourself. Some Java experience is required to do this.

But enough with the introductions. Let's get to the real content...


Introduction to part 4

My employer wants me to keep my resume up to date in both Dutch and English. This means a lot of overhead, because every change should be processed in two documents. A large part of the documents are copies. The header texts are different. A few fields like function title and description are different. But many fields are the same in both languages. My name, birth date, company names and start and end dates are identical. Wouldn't it be nice if I could edit a single document to change my resume in both languages?

That's exactly what we're going to do in part 4 of the XForms tutorial. Header texts and list values are externalized to resource bundles. A few fields are duplicated so they can be filled out in both languages. Source documents are extracted to separate XML documents. Style and layout are specified in an CSS stylesheet. And there is a new button to switch between English and Dutch without using any server side code.

The example in part 3 had an annoying shortcoming. If you deleted all work experiences, the document was unable to create a new work experience. Part 4 demonstrates how XForms bindings can be used to work around this problem.

The example is available online under the following URL. If you want to experiment with the code and modify it, you can download a ZIP file containing all files required by the XForms document. In part 3, the complete example was contained in a single file. From now on, the examples are separated over a set of files. To run the examples, you require Mozilla 1.5 and the latest version of the Mozilla XForms plugin. The examples are not tested in other XForms implementations.


Specifying declarative binding logic

Classic programming paradigms require software developers to implement algorithms telling the computer exactly what to do. As applications grow, developers should find clever ways to support additional features without duplicating code. Code duplication harms maintainability of the software. The clever ways around duplication often harm readability of the code.

In modern software development, developers no longer specify *what* to do or *how* to do it. Instead, they specify a model of their problem and expect their software to interpret the model automatically and provide answers as they are queried. The *what* and *how* are preconfigured under the hood and may be replaced by an alternative implementation without affecting the model specification. An early effort in this direction was PROLOG. PROLOG allows users to input a set of logical constraints. The constraints are supposed to represent a simplified model of reality. The user can ask questions to PROLOG which are automatically answered given the constraints. Because PROLOG is designed to solve logical problems, it is easily capable of providing the answer to a logical quiz from a news paper. As the complexity of the logical model grows, there is a risk of run times for solving problems. After all, the user can only influence the model specification, not the solving algorithm.

After PROLOG, many other products were developed using declarative model specifications for both answering questions or describing the behavior of user interfaces. Most of these products are targeted at a very specific problem domain. Limiting the problem domain allows more adequate solutions for those specific problems.

XForms is an example of such a declarative solution. The domain is XML based Forms. It is very powerful as long as you are developing a form and as long as it is based on XML. As soon as you want to use the technique for any other purpose, it is nearly impossible to get a working result.

The declarative nature of XForms is recognized when you compare them to classical HTML forms. If you want to add any business logic to a classic HTML form, you are forced to implement tiny procedures in JavaScript. Where JavaScript code is error prone and differs between browsers, XForm models will be portable as XForms implementations mature.


The xf:bind tag

The xf:bind tag is one of the most versatile elements available in XForms. It is used for specifying almost any business logic in a form. A rough list of capabilities is:

  • item type specification
  • required element or attribute specification
  • disabled element or attribute specification
  • dynamic calculation of values
  • specification of relevance of an element or attribute
  • constraining values
  • binding nodes or nodesets to IDs

What makes the xf:bind tag even more powerful, is that each of these functionalities is not limited to a single node, but may involve a set of elements. These nodesets are not limited to sets of siblings but may consist of elements anywhere in the source document. XPath queries are used for referencing nodes or node sets. When your experience with XPath grows, you'll find it to be a very powerful way for accessing nodes even in the most complex XML structures.

As any other XForms element, xf:bind dynamically responds to changes in the source documents. In beta implementations of XForms you might find some quirks and bugs in this behavior, but I'm convinced these will be fixed in the final version.


Binding item types

When you're using xf:input elements referring to source document elements, you'll see text input fields in the resulting documents. For specific elements like a birth date, you would expect to use something like an xf:dateInput or an xf:input type="date". In XForms this is a little different. In your xf:model you specify an xf:bind ref="..." type="xs:date" and the input field automatically changes to a date chooser in the resulting document.

By binding elements to XSD item types, XForms decides which view is required for the input element. If the source document element is referenced by more than one input, the item type needs to be specified only once. This prevents duplication and therefore improves maintainability which is important in software development.

Talking about duplication, I was a little bit disappointed that XForms required me to specify the item type in an xf:bind tag. After all, I took the effort to provide a complete XSD XML Schema file for all source documents. XForms seems to offer additional tags to explicitly refer to such XSD files. In the current implementation I was unable to bind an item type without using the xf:bind tag though.




Required elements

In a similar way, XForms allows us to reference a set of elements and specify a required="true()" attribute. As a result, the form cannot be submitted to the server if no value is present for those fields. In the CSS style sheet, I can change the looks of required elements. In the example, these fields have a yellow background and a * postfix behind their labels.

More interesting is to replace the hardcoded "true()" value by a dynamic expression. In the example, the maidenname field is only required when the gender is set to female. Implementing such logic in JavaScript based HTML forms takes a lot more effort and is more error prone.



Disabled/read-only elements

Disallowing user input works the same way. In the example, a user specifying he is male, is unable to input a maidenname. This makes little sense, because the maidenname could have been hided just as well. This example is just a demonstration. A more practical purpose is a field providing the output of a calculation. No input is necessary, because the value results from earlier input.


Calculations

A powerful feature is the ability to calculate values or sets of values. Its purpose is evident in a tax form. But in any other form it is very useful behind the screens. In the example document, we introduce a helper source document containing the outcomes of calculations. The outcomes are used as shorthand notations for long repetitive queries elsewhere in the document.

The example also introduces a shorthand notation without using the helper document. Static texts like headers, labels and hints are provided in two languages in resource bundles. Referring to the text value in the current language involves specifying the current language in each query. Instead of copying these references, the actual values in the current language are copied to their parent elements and resources are referenced assuming they are in the current language.



Source data in multiple languages:



Relevance

Specifying whether an element is relevant or not allows you to hide elements and their respective input elements as needed. In the example, the end date of a work experience is hidden when the current employer is set to "yes".

More importantly, the relevance attribute solves our problem in part 3. The problem was that the form was unable to create a new work experience instance when no template instance was available. Going from at least one experience to two or more was possible. But from zero to one wasn't. In the updated example, there is always an empty template experience present. The relevance binding is used to hide the template instance on screen. When no other experience than the template is available, the screen is empty and shows a button to create the "first" experience, which actually is the second.

When we're going to submit data to the server in a next episode, it is good to keep in mind that XForms automatically strips the irrelevant nodes from the document sent to the server. This means that when you're reloading the form in the client, the template node should be restored server side, or the relevance property should temporarily be disabled during document submission.



Constraining values

In addition to typing and visibility rules, XForms also allows us to specify validity rules over a set of fields. In the demonstration form for example, in a work experience the end date cannot be earlier than the start date. How XForms enforces the constraining rules is explained in the sections on styling and error messages.

Binding nodes to IDs

In software engineering, it is good practice to extract arbitrary numbers and texts from your source code and put them in variables in a central place so they can easily be altered without affecting specific source code. This improves maintainability and prevents duplication. In many cases it takes little effort to make the texts available to users or system administrators in order to customize software without rebuilding the source. I like to refer to these as "resource bundles". When software is distributed in more than one language, you can't do without resource bundles. The example resume form in part 4 demonstrates how resource bundles can be used to dynamically switch from English to Dutch without server interaction.

A naive implementation of resource bundles in XForms would require an XPath query in any label referring to a specific resource. To improve readability however, in our example each label refers to a unique ID. In the model specification in the header of the document, each ID is bound to the corresponding resource element. It is assumed that the referred resource element has already been translated to the current language because of the earlier calculation. The order in which the XForms implementation processes the model is essential for this to work. It turns out that a forced rebuild action is required when the trigger for switching languages is invoked.

Most IDs refer to a singleton resource element. Some IDs refer to a list of elements filling a selection drop down box. A single list element resource can be part of one or more selection lists. In the example model, this depends on the availability of a listreference tag in the resource list. The values "yes" and "no" are shared by two selection boxes, while the value "unknown" is available in only one of them.

I do not believe there is a common standard for working with resources - both singleton and lists - in XForms. What you see here, is a result of custom modeling with an additional source document and clever XPath queries. Feel free to copy the suggested pattern in your own solutions. Any comments on improving the technique are welcome.

Part of the resource bundle source document; keep in mind that the value elements in the current language are copied to their parent resource elements by the earlier calculation binding:



The ID binding declarations in the model:



References to both singleton IDs and lists of resource bundles:


Styling XForms using CSS

In part 3, classic XHTML tables were used for positioning elements. In part 4, the table elements seem to have disappeared. The result on screen still looks like a table though. The trick here is that the style for each input type is declared in the CSS style sheet. The style sheet states that some elements should be represented as a table row and others as a table cell. Additional properties like cell width and background color are provided as well.

At this point, it took a lot of trial and error to get a decent looking form on the screen. I encourage you to take a look at the style sheet and experiment with your own forms. For now, I'll skip the explanation because I miss a complete understanding to write an authoritative explanation pointing out exactly what to do in order to achieve exactly what you want.

I ran into some strange behavior that seemed unpredictable and random to me. It might very well be intended and documented behavior but until the final version of the XForms plugin is released, I blame it on the immaturity. Some of the remaining XHTML paragraph tags you find in the example are quick and dirty workarounds for this behavior.

I'll get back on this as soon as I can. With the xf:bind tag being the main subject in this post, I think the demonstration still shows enough to release it as it is right now.


Error messages

With all the constraints and type definitions the next logical question is what the end user sees when his input violates the rules. If the example had a submit button for sending data to the server, violations should prevent submission with user friendly warning messages. This example does not have a submit button yet. Binding violations result in red colored labels in front of the input fields. For now, it is up to the end user to find out what's wrong by himself.

XForms has an xf:alert tag to provide user friendly messages on binding rules violations. An alert message pops up after changing an input value or before submitting the form to the server. Unfortunately, the alerts also popup in the example when switching languages from English to Dutch. Even worse, Firefox crashes after closing the message boxes. All I can do is send an error report to Microsoft. It's not like Microsoft can help this. But it is still good practice to submit the error reports anyway. This keeps a few of their employees busy and that's what they created the reporting feature for, isn't it?


Hints and help messages

For now, I have left the alert messages out of the example. I did include an xf:hint and an xf:help tag which work the exact same way. I added a small icon to the fields featuring hint- and help messages to indicate to the end user that there is more information there. Specifically, I used the hint and help messages on the fields bound to a bilingual element in the source document. The hint provides a tooltip telling the user to press F1 to see a quick preview of the translation of the targeted field. The help tag is bound to the value in the alternate language and is meant to improve productivity. When you're making your resume, you don't need to switch languages all the time to see what you typed in the other language. A more sophisticated solution is required when the example is extended to support more than two input languages.


Conclusion

With the new binding logic, the example is starting to look like a production quality solution to the challenge provided in part 1 of the tutorial. The main ingredients missing right now are the ability to save data, a lot more detail and a preview of the resulting resume document.

Part 5 of the tutorial will focus on server interaction. It becomes even more interesting when you can store your resume server side and use server side XSLTs to transform the XML document to an actual resume in (X)HTML, PDF or Office document.

If that isn't enough, we can add additional input fields bound to the resource bundles source documents and save these as well. With some extra effort, I think we should be possible to have the XSLTs read both the resume document and the resource bundles document as input for the generated output document. This way the end user can take complete control of both his input in the resume and the header- and label values.

The main open issue is how I am going to make a working live demonstration available. I think my home ADSL line without guaranteed uptime will have to do here. I am afraid this will be available for a limited period only.

One thing is certain though: some Java Servlet programming experience is required! As it turns out, XForms is advanced material. Not a single tutorial available online is going to change that, I've noticed.

Stay tuned!

The example is available online under the following URL. If you want to experiment with the code and modify it, you can download a ZIP file containing all files required by the XForms document.



Tags: | | |


THIS POST IS SUPERSEDED BY A NEW SERIES OF ARTICLES ON XML TECHNOLOGIES AND XFORMS... READ MORE IN PART 5 OF THE XFORMS TUTORIAL...