THIS POST IS SUPERSEDED BY A NEW SERIES OF ARTICLES ON XML TECHNOLOGIES AND XFORMS... READ MORE IN PART 5 OF THE XFORMS TUTORIAL...
Introduction
After a long break, it's time to continue writing the XForms tutorial. The latest preview version of the Mozilla XForms plugin supports the features I planned for part 3. If you want to try the examples presented in the tutorial, please download Firefox 1.5 or later and the latest implementation of the XForms plugin. After installing the plugin, restart firefox and open the example. If you're getting serious with XForms you might also want to try the extension XForms Buddy.
Every episode of the tutorial introduces an XForms feature that clearly demonstrates how XForms sets itself apart from competitive technology. Most importantly it demonstrates the advantages over classic HTML forms. Each feature is an elegant declarative XML aware solution to a common problem in form implementations. Where competitive technologies depend on error-prone client side scripts and workarounds with server interaction, XForms provides a native language for dealing with semi-structured XML documents, multiple name spaces, XML Schema definitions, logical dependencies, advanced input elements and type checking and dynamic updates in the content model.
To stress the importance of the XForms technology, please keep in mind that in XHTML 2.0, classic HTML forms are replaced by XForms. However, this is no guarantee for the actual adoption of XForms in practice. This will depend on standards compliance of future browser versions. It also depends on the web development community. XForms has a steep learning curve. Not only does it require an understanding of the declarative syntax of XForms itself; it also requires a thorough understanding of XML standards. Despite the wide adoption of simple XML notations used for data transfer, relatively few people fully understand advanced XML concepts like namespaces, XML schemas, XSL transformations and the semi-structured nature of an XML document. I'll try to cover these topics as we go.
In this tutorial the code example presented each episode is based on the example from the preceding episode. Every episode is a step towards a full example solution to the problem presented in part 1. The complexity of the examples grows every episode. Complex examples are not suitable as reference material. This is a choice I made when I started the tutorial. Reference material for XForms is widely available on other web sites. Proper tutorials are harder to find. This tutorial expects the reader to start with part 1 and follow the linear step by step plan.
Summary of part 2
The last episode, part 2, was a Hello World introduction to XForms. The key feature demonstrated in the example code, is the dynamic nature of an XForms document. When the user changes input elements, all elements in the resulting view are automatically updated to represent the new data from the content document. The document source shows absolutely no script or action definition that invokes this process. The dynamic changes are a result of the XForms architecture. This architecture separates the data source document from declarative business logic specifications and a dynamic view of the data. The view is a result of the view definition, the logical constraints and change events on the source data document.
One-to-many relations
This part of the tutorial introduces the possibility to implement repeating subforms as an interface to parent-child-relations in XML documents. Data in classic HTML forms is one-dimensional. There is one unique identifier for each input field. A typical resume contains more than one work experience. Classic HTML forms would require manual duplication of input elements or server side interaction for each new work experience. Some classic database interfaces provide parent child views for similar data structures. The interface has a short list of child elements and one form to view or edit a specific child when it is selected. This interface is inspired on the Entity-Relationship-database structure with multiple tables. The main disadvantage of this approach is that it does not feel like you're editing a document. It feels like you're manipulating a database. A proper interface should hide the backend model and show an interface that represents the model the way it is the most familiar to the end user.
Reporting software usually does support repeating elements. The main limitation of reporting software is that it is output-only. There is no way to get changes in the output document back into the source document. Adobe XFA technology is a nice try. The number of repeating subforms is dynamic in the PDF form at render-time. However, once the form is visible on screen, the number of subforms is fixed and the user is limited to changing values within the subform. Adding or removing an instance of the subform is not possible because of the static nature of the PDF viewer. A common solution to this limitation is to provide a fixed and limited number of subform instances. The user can leave subforms empty when they're not needed. There is no way for the user to input more instances of the subform than the arbitrary number specified by the form developer. For an experienced employee writing a resume with a large number of work experiences, this limitation probably has too many undesirable consequences.
XForms allows dynamic instantiation and removal of repeating XML elements. The form developer can provide buttons to insert or delete additional elements or change the order of the elements available. The dynamic form document grows and shrinks in response to user input. Data eventually is sent to the server in XML format. Where the classic HTML form submission data structure is limited to one-dimensional URL-encoded key-value pairs, the XML format allows advanced semi-structured data structures with few limitations but strong expressive power.
Overview of part 3
Enough with the introduction texts. You want real content! You want examples! I have examples! But before I present them to you, please consider reading just a few more words explaining a general concept before we dive into the deep. I think it is important that you fully understand how to properly identify your own custom XML structures within a document that mixes them with other XML structures, both open standards and additional custom document types. To do this, I explain XML namespaces in my own words. After that I switch to actual XForms concepts. I introduce a way of grouping subsets of form elements within the document and abbreviating XPath identifiers within the group. Then I'll demonstrate similar functionality to create repeating groups as an interface to repeating data structures. Finally I will introduce the basics for triggering and handling events so the end user can manipulate the document structure.
Namespace declarations
Some of you are already familiar with XML namespaces. Many of you have seen them in several XML formats. You may have copied them into your own documents to get them to work. But I assume relatively few of you are experienced in inventing your own namespaces for custom document types and their instance documents. Creating custom namespaces and document types is essential in every part of this tutorial.
Please note that namespaces are only used to identify XML elements with a unique String. Namespaces do not provide descriptions of the format. Techniques describing document types are introduced in later parts of the tutorial. Document Type Definitions (DTD) and XML Schema Definitions (XSD) can be used for this purpose. This tutorial will focus on XSDs.
For simplicity, the example in part 2 omitted a namespace declaration for the instance data. The resume XML had no prefix and no namespace definition in the root element. I assumed you were familiar with basic XML notation and you would have no problem reading the namespaces used by mixing XHTML elements and XForms elements. But what about specifying namespaces for your own data?
In my opinion, namespaces are the actual "X" in "XML" (eXtensible markup language). XML documents are extensible because they allow us to mix one XML definition within another XML definition. The example in part 2 shows this concept by mixing XHTML (using the html: prefix) with XForms (the xf: prefix). The use of XForms is not limited to XHTML documents. There are also XForms implementations for SVG models (Scalable Vector Graphics) or Office documents (OpenOffice 2.0). XForms is designed to be modular. Otherwise XForms could have been integrated within XHTML and use the same prefix. Modularity improves the reusability of document type definitions. Reusability is key to set widely accepted standards and push future improvements for both the standard itself and related standards.
Separating XHTML and XForms elements involves more than only adding html: and xml: prefixes. In fact, these prefixes are short-hand-notations for a less common XML notation:
(please replace the square brackets [tag][/tag] by their proper XML equivalents...)
[{http://www.w3.org/1999/xhtml}body]
[{http://www.w3.org/1999/xhtml}p]
Paragraph text
[/{http://www.w3.org/1999/xhtml}p]
[/{http://www.w3.org/1999/xhtml}body]
This can be rewritten as:
[html:body xmlns:html="http://www.w3.org/1999/xhtml"]
[html:p]
Paragraph text
[/html:p]
[/html:body]
This notation improves readability, it prevents duplication and it is less error prone. The prefix text "html:" can be replaced by any other text as desired by the editor of the document. As long as the "xmlns:{prefixtext}" attribute specifies the same and right Uniform Resource Name (URN), the prefix may differ from document to document. For example, some XForm documents use xf:, others use xforms: or any other text. Nevertheless, I do recommend to use readable and descriptive prefixes. Any other randomly chosen prefix, like a:, b:, c:, would confuse human readers of the document. Human readability was one of the key design goals of the XML format. This design goal is best recognized in the redundancies in closing element tags. For computer algorithms something like [/] would be sufficient as a closing tag in a document with correct nesting. Using [/xmltag] and text indention is only meaningful to human readers. A little research on the internet teaches us that this redundancy is a subject of controversy. Some fanatics propose an alternative technique named S-Expressions (or Symbolic Expressions) to save disk space and band width.
Most XML documents declare namespaces in the root element. But Namespace declarations are allowed in any element in the document. The choice of the element used for the namespace declaration decides the scope of the prefix in the document. A declaration in the root element allows you to use the prefix anywhere in the document. Using any other element limits the scope of the prefix to descending elements enclosed in the declaring element. Please be careful this does not lead to duplications of the namespace declaration. A single declaration in a document is best for readability and maintainability. Nevertheless, there are some applications where it is very common to limit the scope of prefix declarations. For example the body of a SOAP message declares the prefix for the body content within the message, not in the SOAP element root.
When an XML structure is not using prefixes, it does not necessarily mean that no URN is specified. The example can also be rewritten as:
[body xmlns="http://www.w3.org/1999/xhtml"]
[p]
Paragraph text
[/p]
[/body]
This notation is recommended for documents using a single namespace. Overhead is avoided and readability improves when you don't need to distinguish namespaces within one document. However, in documents mixing multiple namespaces, I recommend against using the default namespace without prefix. Descriptive prefixes for every namespace prevent false assumptions implicitly made by human readers and editors. To assure the reader that he's reading the document correctly; tags, id-attributes and their references should always be as explicit and descriptive as possible. Choosing id-attributes is covered in a few moments when repeating elements are discussed.
At this point, you know how to handle the prefixes. But what about the URN text these prefixes are referring to? In theory, a Uniform Resource Name could be any text as long as the name is unique for your document type. In practice, some common patterns can be recognized in URNs available in public. For open standards it is common to use URL-notations. Using an URL ensures the uniqueness of the name it provides a descriptive definition of the standard. The host name indicates the source organization of the standard and the path specifies the name, date and or version. In some cases, the URL can be retrieved in a web browser to find additional information. For simple documents not trying to set worldwide standards a common URN notation is "urn:any-name". The examples in this tutorial use this notation for our own document types to separate them from real standards. Any urn:namespace document type is invented by the author. URL namespaces are W3C standards.
In our example document, the source data instance is rewritten as follows:
Grouping elements
In part 2 of the tutorial, references to specific elements in the source document use XPath queries specifying the full path from the data instance documents root to the referenced element. As the document size and depth grows, the duplication in the XForms document increases. For maintainability it is desirable to specify an XPath reference relative to a parent element instead of copying the full path to the root everywhere. An XForms xf:group element can specify a sub-element as the root within a limited scope. Within the group, additional groups can be recursively defined gradually covering every level in the document tree. This results in a more compact XForms document that can easily be adjusted to drastic changes in the document type definition.
In the next part of the tutorial, additional features of xf:group elements are demonstrated. When a group is bound to a specific element, the XForms implementation dynamically shows or hides the group depending on business logic regarding the element. Visibility of a group or an element depends on whether the element is defined as "relevant" or not. This relevance can be specified by declarative rules and conditions that should be matched by the source data document.
In this code example, the xf:group element works well for selecting the section containing personal details and referencing the input elements within the section. But for the work experiences, we would like to repeat a group element for each existing or new experience instance. For this purpose, XForms provides another more specific solution similar to xf:group but targeted at specific functional requirements for repeating element groups.
Repeating elements
To me, repeating elements is the key feature of XForms explained in this part of the tutorial. In earlier implementations of the Mozilla XForms plugin I couldn't get it to work and this was the reason for me to take a break writing the tutorial. Other tutorials on the internet tend to omit this feature or save it for the end as an advanced concept. I like to dive right into the advanced concepts because of the importance of the feature.
Repeating elements are less complicated than they seem. They allow very powerful and user friendly interfaces to be developed with little time and effort. There is no interaction with the server and no client side JavaScripts.
Only Microsoft InfoPath provides similar functionality but that is no W3C standard. InfoPath does not run within an internet browser. It is not part of the XHTML 2 standard which is planned to be the future of the world wide web. InfoPath depends on client side scripting and misses declarative logic handling common problems in form documents. But in defense of InfoPath, it does offer a far more user friendly interface to the form developer. Using wizards, forms can be developed with little technical knowledge in a very short time. The lack of web browser integration is compensated by MS Office integration.
The definition of the xf:repeat element is similar to the xf:group element. Instead of referring to a single element, a nodeset is specified. It may seem as if a single work experience is referenced with "cv:experience". But keep in mind that "cv:experience" XPath query referenced from the enclosing group. In XPath, when more than one cv:experience is available, the query "cv:experience" refers to the complete set of experiences. If you wanted to reference a single experience in the nodeset, then the expression would be something like "cv:experience[cv:company = 'First company']".
In addition to the nodeset, an id-attribute is specified. The id allows you to refer to the set of repeating elements from another part of the XForms document. In theory, the developer is free to choose any id text. Many other XForms references and tutorials on the internet use random id texts like "id0" or "experience" without thinking ahead. I recommend spending a little extra time and effort when you're defining ids. Experienced software developers understand the importance of using descriptive and readable id texts. In the example, the id is "repeat.experience". Earlier in the document, instance data defines its id as "instance.resume". The advantage is that XPath references elsewhere in the document explicitly describe what kind of element they are referring to. Accidental duplication of ids is avoided. You're less likely to refer to the wrong element. Assumptions about child elements are explicitly expressed in the XPath query.
At runtime, both XForms interface elements and XHTML structures within the repeat-tags are copied for each cv:experience in the source document. References to specific elements in each work experience are relative to the enclosing experience element. This is similar to the group element notation. In the example source data a single work experience is provided. To start the actual repeating of elements, an additional experience should be inserted.
Triggers and events
To add and remove experiences in the document, we need two things: a button the user can click to trigger an event and a piece of code that responds to the event and execute the desired action.
The button is defined as an xf:trigger with a label for the text on the screen. The trigger by itself is no different than any other XForms input element. It responds to the specified business logic and triggers events describing user interaction.
The actual code is contained in an xf:action element. The action element has an attribute "ev:event" to specify which kind of event it should respond to. In the example, the action is defined within the trigger element. The XForms specification allows you to define an xf:action outside the trigger element, for example as a child of the XForms root element. As you might expect, there are consequences. The position of the action defines its scope. The insert action is bound to DOMActivate events, but it only executes when the Insert-button is pressed. An action defined outside the trigger and bound to DOMActivate events, responds to both the Insert and the Delete button. For some applications and maybe other event types, this may be desirable logic.
The xf:action element container is defined in the XForms specification. The event itself however is not specific to XForms. XML Events are described and specified in the W3C XML Event specification. This is yet another example of the modular design of XML, XHTML2 and XForms. XForms automatically inherits all the features specified in the XML Events standard. For example, an interesting feature that comes with XML Events is "event bubbling". Event bubbling describes the way an event is dispatched in the Document Object Model (DOM). Dispatching starts with the element that triggered the event. For example, the insert button. In our example, an event is bound to this element, so the action is invoked. When the action is ready, event dispatching continues. The parent element receives a notification of the event. In our example, the parent is not bound to an event. As a result, the event "bubbles" up to the parent of this parent element. This continues recursively until another bound event is encountered or until the document root is reached. With this behavior in mind, it is easier to understand how the scope of an xf:action depends on its location in the XForms document.
For the implementation of the action a set of commands is defined in the XForms specification. No scripting is needed to implement common action handlers in an XForms document. However, the instruction set provided by XForms is extremely limited. It consists of "xf:insert", "xf: copy", "xf:delete" and "xf:setindex". When you're implementing actions, you should follow the KISS principle (Keeping It Stupidly Simple). When you feel the need for implementing more complex actions, you should reconsider your requirements. Most likely there are good reasons why you shouldn't want to implement such complex actions. In general, you can increase the complexity of your form implementation by being creative with XPath queries and XForm business logic. For developers this involves a paradigm shift from procedural progamming to declarative programming. Some experience with the PROLOG philosophy turns out to be helpful. The next parts of this tutorial start introducing XForms tools for business logic declarations.
Implementing the example code, I noticed a strange thing. When an xf:action is defined within an xf:group element, I would expect the ability to use XPath references relative to the xf:group root element. However, it turns out that XPath references within an action should provide the full reference from the instance root to the specified element. This increases the amount of code and harms maintainability. I'm not sure whether this is a quirk in Mozilla or intended behavior from the XForms standard.
Another odd thing I encountered, is the behavior of the insert command. This command does not actually insert a new set of elements, but rather copies an existing set and requires me to set empty values in all the elements. As a result, a minimum of one experience is required for the form to work correctly. When the user deletes the last experience, there is no existing experience to be copied as a new instance. I didn't yet find out whether an XSD specification would solve the problem. I did find another workaround on the internet, which is discussed in part 4 of the tutorial.
Conclusion
In part 3 of the XForms tutorial I explained how XML really is an Extensible Markup Language. I described how namespaces are essential for mixing modular XML document types using both open standards and home grown content definitions. I demonstrated element groups to improve maintainability, repeating elements for advanced data structures, and triggers and actions for user interaction.
In the following part I will demonstrate how declarative business logic can be used to solve some of the shortcomings in the current example form. A hidden empty experience serves as a template for every newly inserted visible experience.
With Firefox 1.5+ and the Mozilla XForms plugin, click this link to open the example.
Tags: XForms | Namespaces | XHTML 2 | MVC
THIS POST IS SUPERSEDED BY A NEW SERIES OF ARTICLES ON XML TECHNOLOGIES AND XFORMS... READ MORE IN PART 5 OF THE XFORMS TUTORIAL...