XML Amsterdam

XML Amsterdam 2015 is over

xmlamsterdam

This year again, XML Amsterdam did connect XML developers worldwide and it’s time to post the links to my presentations.

Many thanks to everyone involved in making this event happen!

XForms Generation (XForms pre-conference day).

Testing with XForms Unit (XForms pre-conference day).

Backtracking and XPDL (conference day)

Share and Enjoy:
  • Identi.ca
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Add to favorites

XForms Unit

Update: After this post I have launched http://xformsunit.org.

XForms forms can be incredibly complex and I have been thinking of an XForms unit test environment for a while. Before I start coding here are some of my thoughts on the topic…

XForms test cases should be native

A common way of testing XForms application is to use a generic purpose web testing tool such as Selenium.

The benefits of such tools is that you can test exactly what is displayed in the browser and simulate user actions. It’s downside is that the tests are expressed in browser related terms rather than using XForms concepts. To write these tests you need to know how XForms will be transformed into HTML and this transformation depends on the XForms implementation being used and may vary between versions.

By contrast a native XForms test environment would allow to express the tests using XForms concepts such as binds, controls and events.

 Principles

The basic idea is to describe a test suite and to add actions to the form to test so that the tests are executed by the XForms engine.

Let’s say we have the following form which is a slightly adapted version of the traditional XForms “hello world”:

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms">
    <head>
        <title>Hello World in XForms</title>
        <xf:model id="model">
            <xf:instance id="instance" xmlns="">
                <data>
                    <PersonGivenName></PersonGivenName>
                    <Greetings></Greetings>
                </data>
            </xf:instance>
            <xf:bind id="greetings" nodeset="/data/Greetings"
                calculate="concat('Hello ', ../PersonGivenName, '. We hope you like XForms!')"/>
        </xf:model>
    </head>
    <body>
        <p>Type your first name in the input box. <br /> If you are running XForms, the output should be displayed in
            the output area.</p>
        <xf:input ref="PersonGivenName" incremental="true">
            <xf:label>Please enter your first name: </xf:label>
        </xf:input>
        <br />
        <xf:output value="Greetings">
            <xf:label>Output: </xf:label>
        </xf:output>
    </body>
</html>

To test that the greeting are what you’d be expecting you would enter a value in the name and check the greetings.

This test can be expressed as:

<?xml version="1.0" encoding="UTF-8"?>
<suite xmlns:xh="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <form src="hello-world.xhtml"/>

    <!-- The test cases -->
    <case id="test-greetings">
        <action>
            <setvalue ref="instance('instance')/PersonGivenName">Eric</setvalue>
        </action>
        <assertEqual>
            <actual ref="instance('instance')/Greetings"/>
            <expected>Hello Eric. We hope you like XForms!</expected>
            <message>The greetings should be the concatenation of "Hello ", the given name and ". We hope you like
                XForms!".</message>
        </assertEqual>
    </case>
</suite>

The generation of the augmented form which will perform the tests can be done in XSLT.

To implement these tests in XForms, we can add an instance initialized with the description of the test suite and updated by XForms actions to reflect the result of the tests:

<xf:instance id="xfu:instance">
    <suite xmlns="">
        <case id="test-greetings">
            <action id="d8e9">
                <setvalue ref="instance('instance')/PersonGivenName" id="d8e11">Eric</setvalue>
            </action>
            <assertEqual id="d8e15" passed="">
                <actual ref="instance('instance')/Greetings" id="d8e17"></actual>
                <expected id="d8e19">Hello Eric. We hope you like XForms!</expected>
                <message id="d8e22">The greetings should be the concatenation of "Hello ", the given name
                    and ". We hope you like XForms!".</message>
            </assertEqual>
        </case>
    </suite>
</xf:instance>

Note how the transformation has added id attributes to the elements of this instance which did not already carry one. These ids will be helpful while writing the actions.

These actions themselves can be coded as:

<xf:dispatch targetid="model" name="xfu:d8e9-action"/>
<xf:action ev:event="xfu:d8e9-action">
    <xf:setvalue ref="instance('instance')/PersonGivenName">Eric</xf:setvalue>
    <xf:recalculate/>
    <xf:dispatch targetid="model" name="xfu:d8e15-action"/>
</xf:action>
<xf:action ev:event="xfu:d8e15-action">
    <xf:setvalue ref="instance('xfu:instance')//*[@id = 'd8e17']" value="instance('instance')/Greetings"/>
    <xf:setvalue ref="instance('xfu:instance')//*[@id = 'd8e15']/@passed" value="(instance('instance')/Greetings) = 'Hello Eric. We hope you like XForms!'"/>
</xf:action>

In this version I have chosen to encapsulate each action and test in its own XForms action and use custom events to trigger these actions one after the other. Also note the xf:recalculate which is necessary to make sure that the greetings are recalculated after we’ve changed the  name.

Now that xfu:instance contains the result of the tests, it could be saved on a server and can also be displayed using XForms controls such as:

<xf:group xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xh="http://www.w3.org/1999/xhtml"
    xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xfu="http://xformsunit.org/"
    ref="instance('xfu:instance')">
    <xh:h3>Test results</xh:h3>
    <xh:dl>
        <xf:repeat nodeset="case">
            <xh:dt><xh:dfn><xf:output ref="@id"></xf:output></xh:dfn></xh:dt>
            <xh:dd><xh:ul>
                    <xf:repeat nodeset="*[@passed]">
                        <xh:li><xf:group ref=".[@passed = 'true']">
                                <xh:span>passed</xh:span>
                            </xf:group><xf:group ref=".[@passed = 'false']">
                                <xh:span>failed</xh:span>
                                <xf:output ref="actual">
                                    <xf:label>Actual : </xf:label>
                                </xf:output>
                                <xf:output ref="expected">
                                    <xf:label>Expected : </xf:label>
                                </xf:output>
                            </xf:group></xh:li>
                    </xf:repeat>
                </xh:ul></xh:dd>
        </xf:repeat>
    </xh:dl>
</xf:group>

The resulting forms works fine with Orbeon Forms:

Screenshot of Orbeon Forms running the tests.
Screenshot of Orbeon Forms running the tests.

It does also work with betterForm:

Screenshot of betterFORM running the tests
Screenshot of betterFORM running the tests

But it fails when run on XSLTForms:

Screenshot of XSLTForms running the tests.
Screenshot of XSLTForms running the tests.

The error raised by XSLTForms is caused by an issue with the support of the xf:recalculate action. A possible workaround is to add a delay in the dispatch action that triggers the test:

<xf:dispatch targetid="model" name="xfu:d8e15-action" delay="1">

Note that this delay causes additional client/server exchanges for server based implementations such as Orbeon Forms and the workaround should be used specifically with XSLTForms.

What you test and what you see

In our test we check that an instance value is what we expect, but can we be sure that this instance value is displayed? This is pretty obvious in our example, but what if there was a typo in the control:

        <xf:output value="greetings">
            <xf:label>Output: </xf:label>
        </xf:output>

Here  the name of the element is lower case and the xf:output will display an empty string but the test will still pass.

The xf:output could also be embedded in more complex xf:group elements, such as:

         <xf:group ref=".[starts-with(PersonGivenName, 'J')]">
            <xf:output value="Greetings">
                <xf:label>Output: </xf:label>
            </xf:output>
        </xf:group>

Here the greetings are displayed only when the name starts with a “J” but, again, the test still passes.

The visibility of the greetings could also be affected by class or style attributes using AVTs:

        <div style="{if (starts-with(PersonGivenName, 'J')) then '' else 'display: none' }">
            <xf:output value="Greetings">
                <xf:label>Output: </xf:label>
            </xf:output>
        </div>

The effect would, again, be to display the greetings only if the name starts with a “J” but this would be much more complex to detect.

What’s missing here is the ability of functions to check the status of the controls themselves rather than instance values.

Orbeon Forms does provide extension functions working on controls which may be useful but are specific to this implementation.

 Introspection

More generally speaking there is a lack of standard introspection functions, not only for controls but also on instances and testing if an instance node is relevant, readonly, required or valid is not possible without using extension functions. Some (but not all) these needs are covered by EXForms functions but their support by actual implementations has to be checked.

Conclusion

Despite some limitations there seems to be a nice potential in a native XForms test framework and of course your feedback is most welcome.

 

Share and Enjoy:
  • Identi.ca
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Add to favorites

When MVC becomes a burden for XForms – XML London 2013

This paper, presented at XML London 2013, is also available as a presentation and as a screencast:

Abstract

XForms is gaining traction and is being used to develop complex forms, revealing its strengths but also its weaknesses.

One of the latest is not specific to XForms but inherent to the MVC (Model View Controller) architecture which is one of the bases of XForms.

In this talk we see how the MVC architecture dramatically affect the modularity and reusabilty of XForms developments and some of the solutions used to work around this flaw.

Practice: a quiz

Let’s start with a quiz…

Basic XForms

Question

Given the following instance:

<figures>
   <line>
      <length>
         <value>10</value>
         <unit>in</unit>
      </length>
   </line>
</figures>

implement a standard XForms 1.1 form displaying the following user interface:

Answer

Model:

<xf:model>
   <xf:instance>
      <figures>
         <line>
            <length>
               <value>10</value>
               <unit>in</unit>
            </length>
         </line>
      </figures>
   </xf:instance>
</xf:model>

View:

<xf:group ref="line/length">
   <xf:input ref="value">
      <xf:label>Length: </xf:label>
   </xf:input>
   <xf:select1 ref="unit">
      <xf:label></xf:label>
      <xf:item>
         <xf:label>pixels</xf:label>
         <xf:value>px</xf:value>
      </xf:item>
      <xf:item>
         <xf:label>font size</xf:label>
         <xf:value>em</xf:value>
      </xf:item>
      <xf:item>
         <xf:label>font height</xf:label>
         <xf:value>ex</xf:value>
      </xf:item>
      <xf:item>
         <xf:label>inches</xf:label>
         <xf:value>in</xf:value>
      </xf:item>
      <xf:item>
         <xf:label>centimeters</xf:label>
         <xf:value>cm</xf:value>
      </xf:item>
      <xf:item>
         <xf:label>millimeters</xf:label>
         <xf:value>mm</xf:value>
      </xf:item>
      <xf:item>
         <xf:label>points</xf:label>
         <xf:value>pt</xf:value>
      </xf:item>
      <xf:item>
         <xf:label>picas</xf:label>
         <xf:value>pc</xf:value>
      </xf:item>
      <xf:item>
         <xf:label>%</xf:label>
         <xf:value>%</xf:value>
      </xf:item>
   </xf:select1>
</xf:group>

Using instances and actions

Question

Implement the same user interface if the instance uses the CSS2 / SVG 1.1 conventions for sizes:

<xf:instance id="main">
   <figures>
      <line length="10in"/>
   </figures>
</xf:instance>

Answer

Model:

<xf:model>
   <xf:instance id="main">
      <figures>
         <line length="10in"/>
      </figures>
   </xf:instance>
   <xf:instance id="split">
      <line>
         <length>
            <value/>
            <unit/>
         </length>
      </line>
   </xf:instance>
   .../...
</xf:model>

View:

<xf:group ref="instance('split')/length">
   <xf:input ref="value" id="length-control">
      <xf:label>Length: </xf:label>
   </xf:input>
   <xf:select1 ref="unit" id="unit-control">
      <xf:label/>
      <xf:item>
         <xf:label>pixels</xf:label>
         <xf:value>px</xf:value>
      </xf:item>
      .../...
      <xf:item>
         <xf:label>%</xf:label>
         <xf:value>%</xf:value>
      </xf:item>
   </xf:select1>
</xf:group>

Controller:

<xf:model>
   .../...
   <xf:action ev:event="xforms-ready">
      <xf:setvalue ref="instance('split')/length/value" value="translate(instance('main')/line/@length, '%incmptxe', '')"/>
      <xf:setvalue ref="instance('split')/length/unit" value="translate(instance('main')/line/@length, '0123456789', '')"/>
   </xf:action>
   <xf:action ev:event="xforms-value-changed" ev:observer="length-control">
      <xf:setvalue ref="instance('main')/line/@length" value="concat(instance('split')/length/value, instance('split')/length/unit)"/>
   </xf:action>
   <xf:action ev:event="xforms-value-changed" ev:observer="unit-control">
      <xf:setvalue ref="instance('main')/line/@length" value="concat(instance('split')/length/value, instance('split')/length/unit)"/>
   </xf:action>
</xf:model>

Modularity

Question

Still using XForms 1.1 standard features, extend this user interface to edit the height and width of a rectangle:

<xf:instance id="main">
   <figures>
      <rectangle height="10in" width="4em"/>
   </figures>
</xf:instance>

Hint: copy/paste is your friend!

Answer

Model:

<xf:model>
   <xf:instance id="main">
      <figures>
         <rectangle height="10in" width="4em"/>
      </figures>
   </xf:instance>
   <xf:instance id="height">
      <height>
         <value/>
         <unit/>
      </height>
   </xf:instance>
   .../...
   <xf:instance id="width">
      <width>
         <value/>
         <unit/>
      </width>
   </xf:instance>
   .../...
</xf:model>

View:

<xf:group ref="instance('height')">
   <xf:input ref="value" id="height-value-control">
      <xf:label>Height: </xf:label>
   </xf:input>
   <xf:select1 ref="unit" id="height-unit-control">
      <xf:label/>
      <xf:item>
         <xf:label>pixels</xf:label>
         <xf:value>px</xf:value>
      </xf:item>
      .../...
   </xf:select1>
</xf:group>
<xh:br/>
<xf:group ref="instance('width')">
   <xf:input ref="value" id="width-value-control">
      <xf:label>Width: </xf:label>
   </xf:input>
   <xf:select1 ref="unit" id="width-unit-control">
      <xf:label/>
      <xf:item>
         <xf:label>pixels</xf:label>
         <xf:value>px</xf:value>
      </xf:item>
      .../...
   </xf:select1>
</xf:group>

Controller:

<xf:model>
   .../...
   <xf:action ev:event="xforms-ready">
      <xf:setvalue ref="instance('height')/value" value="translate(instance('main')/rectangle/@height, '%incmptxe', '')"/>
      <xf:setvalue ref="instance('height')/unit" value="translate(instance('main')/rectangle/@height, '0123456789', '')"/>
   </xf:action>
   <xf:action ev:event="xforms-value-changed" ev:observer="height-value-control">
      <xf:setvalue ref="instance('main')/rectangle/@height" value="concat(instance('height')/value, instance('height')/unit)"/>
   </xf:action>
   <xf:action ev:event="xforms-value-changed" ev:observer="height-unit-control">
      <xf:setvalue ref="instance('main')/rectangle/@height" value="concat(instance('height')/value, instance('height')/unit)"/>
   </xf:action>
   .../...
   <xf:action ev:event="xforms-ready">
      <xf:setvalue ref="instance('width')/value" value="translate(instance('main')/rectangle/@width, '%incmptxe', '')"/>
      <xf:setvalue ref="instance('width')/unit" value="translate(instance('main')/rectangle/@width, '0123456789', '')"/>
   </xf:action>
   <xf:action ev:event="xforms-value-changed" ev:observer="width-value-control">
      <xf:setvalue ref="instance('main')/rectangle/@width" value="concat(instance('width')/value, instance('width')/unit)"/>
   </xf:action>
   <xf:action ev:event="xforms-value-changed" ev:observer="width-unit-control">
      <xf:setvalue ref="instance('main')/rectangle/@width" value="concat(instance('width')/value, instance('width')/unit)"/>
   </xf:action>
</xf:model>

Homework: repeated content

Still using standard XForms features, extend this form to support any number of rectangles in the instance.

Hint: you will not be able to stick to atomic instances for the width and height but act more globally and maintain instances with a set of dimensions which you’ll have to keep synchronized with the main instance when rectangles are inserted or deleted.

What’s the problem?

XForms lacks a feature to define and use “components” that would package a group of controls together with their associated model and actions.

Theory: the MVC design pattern

XForms describes itself as a MVC architecture:

An XForm allows processing of data to occur using three mechanisms:

  • a declarative model composed of formulae for data
    calculations and constraints, data type and other property declarations, and data submission
    parameters
  • a view layer composed of intent-based user interface
    controls
  • an imperative controller for orchestrating data
    manipulations, interactions between the model and view layers, and data submissions.

Micah Dubinko argues that the mapping is more obvious with Model-view-presenter
(MVP)
, a derivative of the MVC software pattern but that’s not the point I’d like to make and
I’ll stick to the MVC terminology where:

  • The model is composed of XForms instances and binds
  • The view is composed of the XForms controls together with the HTML elements and CSS stylesheets
  • The controller is composed of the actions

Orbeon Form Builder/Form Runner go one step forward and add a fourth concern for localization and we get a model/view/localization/controller pattern.

This separation of concerns is great to differentiate different roles and split work between specialists but doesn’t play well with modularity and reusability.

I am currently working on a project to develop big and complex forms and this is becoming one of the biggest issues: these forms share a number of common fields and group of fields and, not even speaking of sharing these definitions, this separation of concerns adds a significant burden when copying these definitions from one form to another.

To copy a field from one form to another you need to copy definitions from the model, the view, the localization and the controller and can’t just copy a “component”.

And of course, there is no easy way to reuse common components instead of copying them.

This kind of issue is common with the MVC design pattern and the Hierarchical model–view–controller (HMVC) has been introduced for this purpose, but how can we use such a pattern with XForms?

Solutions

A number of solutions are being used to work around this issue with XForms.

Copy/Paste

This is what we’ve done for our quiz and we’ve seen that this is easy -but very verbose and hard to maintain- until we start to deal with repeated content.

I would guess that this is the most common practice when fields (or group of fields) are being reused in XForms though!

XForms generation or templating

We’re XML developers, aren’t we? When something is verbose we can use XSLT or any other tool to generate it and XForms is no exception.

XForms can be generated from any kind of model including annotated schemas or other vocabularies such as DDI (we’ll be presenting this option at the Balisage International Symposium on Native XML User Interfaces in August.

Projects without any obvious model formats in mind often chose to transform simplified versions of XForms into plain XForms. In that case the approach may tends toward a templating system where placeholders are inserted into XForms documents to be transformed into proper XForms.

We may want for instance to define <my:dimension/> placeholders which would look like XForms controls and generate the whole model, view and controller XForms definitions.

The source form would then be something as simple as:

<xh:html xmlns:xh="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:my="http://ns.dyomedea.com/my-components/">
   <xh:head>
      <xh:title>Template</xh:title>
      <xf:model>
         <xf:instance id="main">
            <figures>
               <rectangle height="10in" width="4em"/>
            </figures>
         </xf:instance>
      </xf:model>
   </xh:head>
   <xh:body>
      <my:dimension ref="rectangle/@height">
         <xf:label>Height</xf:label>
      </my:dimension>
      <br/>
      <my:dimension ref="rectangle/@width">
         <xf:label>Width</xf:label>
      </my:dimension>
   </xh:body>
</xh:html>

A simplistic version of a transformation to process this example is not overly complex. The controls are quite easy to generate from the placeholders:

<xsl:template match="my:dimension">
    <xsl:variable name="id" select="if (@id) then @id else generate-id()"/>
    <xf:group ref="instance('{$id}-instance')">
        <xf:input ref="value" id="{$id}-value-control">
            <xsl:apply-templates/>
        </xf:input>
        <xf:select1 ref="unit" id="{$id}-unit-control">
            <xf:label/>
            <xf:item>
                <xf:label>pixels</xf:label>
                <xf:value>px</xf:value>
            </xf:item>
            .../...
        </xf:select1>
    </xf:group>
</xsl:template>

A model can be appended to the <xh:head/> element:

<xsl:template match="xh:head">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" mode="#current"/>
        <xf:model>
            <xsl:apply-templates select="//my:dimension" mode="model"/>
        </xf:model>
    </xsl:copy>
</xsl:template>

And the instances and actions can be generated similarly:

<xsl:template match="my:dimension" mode="model">
    <xsl:variable name="id" select="if (@id) then @id else generate-id()"/>
    <xf:instance id="{$id}-instance">
        <height>
            <value/>
            <unit/>
        </height>
    </xf:instance>
    <xf:action ev:event="xforms-ready">
        <xf:setvalue ref="instance('{$id}-instance')/value"
            value="translate(instance('main')/{@ref}, '%incmptxe', '')"/>
        <xf:setvalue ref="instance('{$id}-instance')/unit"
            value="translate(instance('main')/{@ref}, '0123456789', '')"/>
    </xf:action>
    <xf:action ev:event="xforms-value-changed" ev:observer="{$id}-value-control">
        <xf:setvalue ref="instance('main')/{@ref}"
            value="concat(instance('{$id}-instance')/value, instance('{$id}-instance')/unit)"/>
    </xf:action>
    <xf:action ev:event="xforms-value-changed" ev:observer="{$id}-unit-control">
        <xf:setvalue ref="instance('main')/{@ref}"
            value="concat(instance('{$id}-instance')/value, instance('{$id}-instance')/unit)"/>
    </xf:action>
</xsl:template>

As always, the devil is in details and this would be far from perfect:

  • In actions, references to the main instance do not take into account the context node under which the <my:dimension/> placeholder is defined (paths are therefore
    expected to be relative to the default instance). Mimicking the behavior of an XForms control and its support of the context node would be much more challenging.
  • Supporting repetitions would be another challenge.

Orbeon Forms’ XBL implementation

Orbeon’s
component architecture
is inspired by XBL 2.0 which describes itself as:

XBL (the Xenogamous Binding Language) describes the ability to associate elements in a document with script, event handlers, CSS, and more complex content models, which can be stored in another document. This can be used to re-order and wrap content so that, for instance, simple HTML or XHTML markup can have complex CSS styles applied without requiring that the markup be polluted with multiple semantically neutral div elements.It can also be used to implement new DOM interfaces, and, in conjunction with other specifications, enables arbitrary tag sets to be implemented as widgets. For example, XBL could be used to implement the form controls in XForms or HTML.
XBL 2.0

Even if this specification is no longer maintained by the W3C Web Applications Working Group, the concepts described in XBL 2.0 fit very nicely in the context of XForms documents even though the syntax may sometimes look strange, such as when CSS selectors are used where XPath patterns would look more natural in XForms documents.

Note

The syntax of XBL declarations has been changed between Orbeon Forms version 3 and 4. The syntax shown in this paper is the syntax of version 4.

The definition of an XBL component to implement our dimension widget would be composed of three parts: handlers, implementation and template:

<xbl:binding id="my-dimension" element="my|dimension" xxbl:mode="lhha binding value">
   <xbl:handlers>
      .../...
   </xbl:handlers>
   <xbl:implementation>
      .../...
   </xbl:implementation>
   <xbl:template>
      .../...
   </xbl:template>
</xbl:binding>

A fourth element could be added to define component specific resources such as CSS stylesheets.

The XForms component’s model goes into the implementation:

<xbl:implementation>
   <xf:model id="my-dimension-model">
      <xf:instance id="my-dimension-instance">
         <dimension>
            <value/>
            <unit/>
         </dimension>
      </xf:instance>
      .../...
</xbl:implementation>

The XForms component’s controls are defined into the template:

<xbl:template>
   <xf:input ref="value" id="my-dimension-value-control"/>
   <xf:select1 ref="unit" id="my-dimension-unit-control">
      <xf:label/>
      <xf:item>
         <xf:label>pixels</xf:label>
         <xf:value>px</xf:value>
      </xf:item>
      .../...
   </xf:select1>
</xbl:template>

The XForms actions are split between the handlers and the implementation (or the template): handlers are used to define actions triggered by events which are external to the component (such as in our case xforms-ready) while traditional XForms actions are used to handle events “internal” to the component such as user actions.

The handlers would thus be:

<xbl:handlers>
   <xbl:handler event="xforms-enabled xforms-value-changed">
      <xf:setvalue ref="instance('my-dimension-instance')/value" 
          value="translate(xxf:binding('my-dimension'), '%incmptxe', '')"/>
      <xf:setvalue ref="instance('my-dimension-instance')/unit" 
          value="translate(xxf:binding('my-dimension'), '0123456789', '')"/>
   </xbl:handler>
</xbl:handlers>

And the remaining actions:

<xbl:implementation>
   <xf:model id="my-dimension-model">
      .../...
      <xf:setvalue ev:event="xforms-value-changed" ev:observer="my-dimension-value-control" 
          ref="xxf:binding('my-dimension')" 
          value="concat(instance('my-dimension-instance')/value, instance('my-dimension-instance')/unit)"/>
      <xf:setvalue ev:event="xforms-value-changed" ev:observer="my-dimension-unit-control" 
          ref="xxf:binding('my-dimension')" 
          value="concat(instance('my-dimension-instance')/value, instance('my-dimension-instance')/unit)"/>
   </xf:model>
</xbl:implementation>

I won’t go into the details which are described in Orbeon’s XBL – Guide to Using and Writing XBL Components but it is worth noting that there is a strict encapsulation of both the model, the view and the controller of this component that seen from the outside acts as a standard XForms control.

Of course, this component can be used as a standard XForms control:

<xh:body>
   <my:dimension ref="rectangle/@height">
      <xf:label>Height</xf:label>
   </my:dimension>
   <br/>
   <my:dimension ref="rectangle/@width">
      <xf:label>Width</xf:label>
   </my:dimension>
</xh:body>

The complete form with the component definition would be:

<?xml-stylesheet href="xsltforms/xsltforms.xsl" type="text/xsl"?>
<?xsltforms-options debug="yes"?>
<xh:html xmlns:xh="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:xxf="http://orbeon.org/oxf/xml/xforms" xmlns:ev="http://www.w3.org/2001/xml-events"
   xmlns:xbl="http://www.w3.org/ns/xbl" xmlns:xxbl="http://orbeon.org/oxf/xml/xbl"
   xmlns:fr="http://orbeon.org/oxf/xml/form-runner" xmlns:my="http://ns.dyomedea.com/my-components/">
   <xh:head>
      <xh:title>Simple XBL Component</xh:title>
      <xbl:xbl script-type="application/xhtml+xml">
         <xbl:binding id="my-dimension" element="my|dimension" xxbl:mode="lhha binding value">
            <xbl:handlers>
               <xbl:handler event="xforms-enabled xforms-value-changed">
                  <xf:setvalue ref="instance('my-dimension-instance')/value" value="translate(xxf:binding('my-dimension'), '%incmptxe', '')"/>
                  <xf:setvalue ref="instance('my-dimension-instance')/unit" value="translate(xxf:binding('my-dimension'), '0123456789', '')"/>
               </xbl:handler>
            </xbl:handlers>
            <xbl:implementation>
               <xf:model id="my-dimension-model">
                  <xf:instance id="my-dimension-instance">
                     <dimension>
                        <value/>
                        <unit/>
                     </dimension>
                  </xf:instance>
                  <xf:setvalue ev:event="xforms-value-changed" ev:observer="my-dimension-value-control" ref="xxf:binding('my-dimension')" value="concat(instance('my-dimension-instance')/value, instance('my-dimension-instance')/unit)"/>
                  <xf:setvalue ev:event="xforms-value-changed" ev:observer="my-dimension-unit-control" ref="xxf:binding('my-dimension')" value="concat(instance('my-dimension-instance')/value, instance('my-dimension-instance')/unit)"/>
               </xf:model>
            </xbl:implementation>
            <xbl:template>
               <xf:input ref="value" id="my-dimension-value-control"/>
               <xf:select1 ref="unit" id="my-dimension-unit-control">
                  <xf:label/>
                  <xf:item>
                     <xf:label>pixels</xf:label>
                     <xf:value>px</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>font size</xf:label>
                     <xf:value>em</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>font height</xf:label>
                     <xf:value>ex</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>inches</xf:label>
                     <xf:value>in</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>centimeters</xf:label>
                     <xf:value>cm</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>millimeters</xf:label>
                     <xf:value>mm</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>points</xf:label>
                     <xf:value>pt</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>picas</xf:label>
                     <xf:value>pc</xf:value>
                  </xf:item>
                  <xf:item>
                     <xf:label>%</xf:label>
                     <xf:value>%</xf:value>
                  </xf:item>
               </xf:select1>
            </xbl:template>
         </xbl:binding>
      </xbl:xbl>

      <xf:model>
         <xf:instance id="main">
            <figures>
               <rectangle height="10in" width="4em"/>
            </figures>
         </xf:instance>

      </xf:model>
   </xh:head>
   <xh:body>
      <my:dimension ref="rectangle/@height">
         <xf:label>Height</xf:label>
      </my:dimension>
      <br/>
      <my:dimension ref="rectangle/@width">
         <xf:label>Width</xf:label>
      </my:dimension>

      <fr:xforms-inspector/>
   </xh:body>
</xh:html>

Subforms

Subforms are implemented by XSLTForms and betterFORM. They have been considered for inclusion in XForms 2.0 but no consensus have been reached and they won’t be included in 2.0.

There are a number of differences between the XSLTForms and betterFORM implementations but the principle -and the shortcomings- are the same.

The basic principle behind subforms is to embed (or load) a form within another one. This embedding must be specifically performed using an <xf:load> action with a @show="embed" attribute. Subforms can also be unloaded.

The fact that subforms are explicitly loaded and unloaded in their “master” form is a key feature for big forms where this mechanism reduces the consumption of resources and leads to important performance improvements.

Subforms, betterFORM flavor

Subforms are described, in the betterFORM documentation, as a way to avoid redundancies and keep the documents maintainable:

As XForms follows a MVC architecture the XForms model is the first logical candidate when decomposing larger forms into smaller pieces. Aggregating more complex forms from little snippets of UI (or snippets of a model) is a limited approach as the interesting parts are located on the bind Elements. This is where controls learn about their constraints, states, calculations and data types. Instead of just glueing pieces of markup together the inclusion of complete models allow the reuse of all the semantics defined within them.
betterFORM
“Modularizing forms”

Joern Turner, founder of Chiba and co-founder of betterFORM, makes it clear that subforms haven’t been introduced to implement components, though:

Sorry i need to get a bit philosophic here but subforms are called subforms as they are *not* components ;) I don’t want to dive into academic discussions here but the main difference for us is that from a component you would expect to use it as a part of a form as a means to edit one or probably several values in your form and encapsulate the editing logic inside of it. A subform on the other hand should be designed to be completely standalone. Typically we build our subforms as complete xhtml documents which can be run and tested standalone without being a part of a host document.
Joern Turner on the betterform-users mailing list

A proper solution for components, based on Web Components) should be implemented in betterFORM 6:

We have also considered to implement this [XBL] but decided against it due to the acceptance and future of XBL and due to the fact that we found it overly complex and academic. We will come up with our own component model in betterFORM 6 which will orient at more modern approaches (Web Components).
Joern Turner on the betterform-users mailing list

In the meantime it is still possible to use subforms to design component like features assuming we take into account the following constraints:

  • Communications between the master form and the subform are done using either
    in memory submissions (ContextSubmissionHandler identified by a model:
    pseudo protocol), the instanceOfModel() function which gives access to
    instances from other models or custom events passing context information.
  • There is no id collision between the main form and the subforms which are loaded
    simultaneously.

This second constraint should be released in the future but the current version of the processor doesn’t address it. In practice it means that in our sample we cannot load simultaneously an instance of the subform to edit the width and a second instance to edit the height but we can still take a “master/slave approach” where a single instance of the subform will be used to edit the width and the height separately or mimic an “update in place feature” where an instance of the subform will replace the display of the width or height.

A way to implement our example using these principles could be:

  • In the master form:
    • Define an instance used as an interface with the subform to carry the
      value to edit and identify the active subform instance.
    • Include triggers to load and unload subforms.
    • Define actions to load and unload the subforms and maintain the
      “interface” instance.
    • Control when to display the triggers to avoid that simultaneous loads of
      the subform.
  • In the subforms:
    • Synchronize the local model with the instance used as an interface.
    • Perform all the logic attached to the component.

The master form would then be:

<xh:html xmlns:xh="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events"
    xmlns:xf="http://www.w3.org/2002/xforms">
    <xh:head>
        <xh:title>Subforms</xh:title>
        <xf:model id="master">
            <xf:instance id="main">
                <figures>
                    <rectangle height="10in" width="4em"/>
                </figures>
            </xf:instance>

            <!-- Instance used as an "interface" with the subform -->
            <xf:instance id="dimension-interface">
                <dimension active=""/>
            </xf:instance>
        </xf:model>

        <!-- Dirty hack to style controls inline -->
        <xh:style type="text/css"><![CDATA[

.xfContainer div {
    display: inline !important;
}

.xfContainer span {
    display: inline !important;
}
]]>
        </xh:style>
    </xh:head>
    <xh:body>
        <xf:group ref="rectangle">
            <!-- Height -->
            <xf:group ref="@height">
                <xf:label>Height: </xf:label>
                <!-- This should be displayed when the subform is not editing the height -->
                <xf:group ref=".[instance('dimension-interface')/@active!='height']">
                    <xf:output ref="."/>
                    <!-- Display the trigger when the subform is not loaded anywhere -->
                    <xf:trigger ref=".[instance('dimension-interface')/@active = '']">
                        <xf:label>Edit</xf:label>
                        <xf:action ev:event="DOMActivate">
                            <!-- Set the value of the interface instance -->
                            <xf:setvalue ref="instance('dimension-interface')" value="instance('main')/rectangle/@height"/>
                            <!-- Remember that we are editing the height -->
                            <xf:setvalue ref="instance('dimension-interface')/@active">height</xf:setvalue>
                            <!-- Load the subform -->
                            <xf:load show="embed" targetid="height" resource="subform-embedded.xhtml"/>
                        </xf:action>
                    </xf:trigger>
                </xf:group>
                <xh:div id="height"/>
                <!-- This should be displayed only when we're editing the height -->
                <xf:group ref=".[instance('dimension-interface')/@active='height']">
                    <xf:trigger>
                        <xf:label>Done</xf:label>
                        <xf:action ev:event="DOMActivate">
                            <!-- Copy the value from the interface instance -->
                            <xf:setvalue value="instance('dimension-interface')" ref="instance('main')/rectangle/@height"/>
                            <!-- We're no longer editing any dimension -->
                            <xf:setvalue ref="instance('dimension-interface')/@active"/>
                            <!-- Unload the subform -->
                            <xf:load show="none" targetid="height"/>
                        </xf:action>
                    </xf:trigger>
                </xf:group>
            </xf:group>
            <br/>
            <!-- Width -->
            <xf:group ref="@width">
                <xf:label>Width: </xf:label>
                <xf:group ref=".[instance('dimension-interface')/@active!='width']">
                    <xf:output ref="."/>
                    <xf:trigger ref=".[instance('dimension-interface')/@active = '']">
                        <xf:label>Edit</xf:label>
                        <xf:action ev:event="DOMActivate">
                            <xf:setvalue ref="instance('dimension-interface')" value="instance('main')/rectangle/@width"/>
                            <xf:setvalue ref="instance('dimension-interface')/@active">width</xf:setvalue>
                            <xf:load show="embed" targetid="width" resource="subform-embedded.xhtml"/>
                        </xf:action>
                    </xf:trigger>
                </xf:group>
                <xh:div id="width"/>
                <xf:group ref=".[instance('dimension-interface')/@active='width']">
                    <xf:trigger>
                        <xf:label>Done</xf:label>
                        <xf:action ev:event="DOMActivate">
                            <xf:setvalue value="instance('dimension-interface')" ref="instance('main')/rectangle/@width"/>
                            <xf:setvalue ref="instance('dimension-interface')/@active"/>
                            <xf:load show="none" targetid="width"/>
                        </xf:action>
                    </xf:trigger>
                </xf:group>
            </xf:group>
        </xf:group>
    </xh:body>
</xh:html>

And the subform:

<xh:div xmlns:xh="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events"
    xmlns:xf="http://www.w3.org/2002/xforms">
    <xf:model id="dimension-model">
        <xf:instance id="concat">
            <data/>
        </xf:instance>
        <xf:instance id="split">
            <height>
                <value/>
                <unit/>
            </height>
        </xf:instance>
        <!-- Get the value from the "interface" instance and initialize the   -->
        <xf:submission id="get-dimension-value" resource="model:master#instance('dimension-interface')/*"
            replace="instance" method="get">
            <xf:action ev:event="xforms-submit-done">
                <!--<xf:message level="ephemeral">Subform has updated itself.</xf:message>-->
                <xf:setvalue ref="instance('split')/value" value="translate(instance('concat'), '%incmptxe', '')"/>
                <xf:setvalue ref="instance('split')/unit" value="translate(instance('concat'), '0123456789', '')"/>
            </xf:action>
            <xf:message ev:event="xforms-submit-error" level="ephemeral">Error while subform update.</xf:message>
        </xf:submission>
        <xf:send ev:event="xforms-ready" submission="get-dimension-value"/>
        <xf:submission id="set-dimension-value" resource="model:master#instance('dimension-interface')/*" replace="none"
            method="post">
            <xf:action ev:event="xforms-submit-done">
                <!--<xf:message level="ephemeral">Main form has been updated</xf:message>-->
            </xf:action>
            <xf:message ev:event="xforms-submit-error" level="ephemeral">Error while main form update.</xf:message>
        </xf:submission>
    </xf:model>
    <xf:group ref="instance('split')">
        <xf:input ref="value">
            <xf:action ev:event="xforms-value-changed">
                <xf:setvalue ref="instance('concat')" value="concat(instance('split')/value, instance('split')/unit)"/>
                <xf:send submission="set-dimension-value"/>
            </xf:action>
        </xf:input>
        <xf:select1 ref="unit">
            <xf:action ev:event="xforms-value-changed">
                <xf:setvalue ref="instance('concat')" value="concat(instance('split')/value, instance('split')/unit)"/>
                <xf:send submission="set-dimension-value"/>
            </xf:action>
            <xf:item>
                <xf:label>pixels</xf:label>
                <xf:value>px</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>font size</xf:label>
                <xf:value>em</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>font height</xf:label>
                <xf:value>ex</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>inches</xf:label>
                <xf:value>in</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>centimeters</xf:label>
                <xf:value>cm</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>millimeters</xf:label>
                <xf:value>mm</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>points</xf:label>
                <xf:value>pt</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>picas</xf:label>
                <xf:value>pc</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>%</xf:label>
                <xf:value>%</xf:value>
            </xf:item>
        </xf:select1>
    </xf:group>
</xh:div>

The code for defining the subform has the same level of complexity than the definition of the XBL in Orbeon Forms but a lot of geeky stuff needs to be added around the invocation of the form which becomes tricky.

From a user perspective, the page would initially look like:

When a user clicks on one of the “Edit” buttons, the corresponding subform is loaded (note that all the “Edit” buttons have disappeared):

Once the user is done editing the values in this subform, (s)he can click on “Done” to come back to a state where both the height and width are displayed and can be edited:

The presentation can be improved replacing for instance the buttons by trendy icons but we had to bend our requirements to get something that can be implemented with subforms.

Of course here we are misusing subforms to implement components, something which was not a design goal, and it’s not surprising that the resulting code is more verbose and that we’ve had to accept a different user interface. The future component feature announced by Joern Turner should solve these glitches.

Subforms, XSLTForms flavor

The support of subforms in XSLTForms is illustrated by a sample: a writers.xhtml master form embeds a books.xhtml subform.

The main principle behind this subform implementation appears to be the same than for betterFORM but there are some important differences between these two implementations:

  • XSLTForms doesn’t isolate the models from the master form and its subform and it is
    possible to access directly to any instance of the master form from the subforms.
  • The features to communicate between models implemented by betterFORM are thus not necessary and do not exist in XSLTForms.
  • The context node is not isolated and is available directly from the controls in the
    subform (see the writers/books example for an illustration.
  • A specific action (xf:unload) is used to unload subforms in XSLTForms while an xf:load action with an @show="none" attribute is used in betterFORM for the same purpose.

With these differences, the code developed for betterFORM could be adapted to work with XSLTForms as:

<?xml-stylesheet href="xsltforms/xsltforms.xsl" type="text/xsl"?>
<?xsltforms-options debug="yes"?>
<xh:html xmlns:xh="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events"
   xmlns:xf="http://www.w3.org/2002/xforms">
   <xh:head>
      <xh:title>Subforms</xh:title>
      <xf:model id="master">
         <xf:instance id="main">
            <figures>
               <rectangle height="10in" width="4em"/>
            </figures>
         </xf:instance>

         <!-- Instance used as an "interface" with the subform -->
         <xf:instance id="dimension-interface">
            <dimension active=""/>
         </xf:instance>
      </xf:model>

      <!-- Dirty hack to style controls inline -->
      <xh:style type="text/css"><![CDATA[

.xforms-group-content, .xforms-group, span.xforms-control, .xforms-label {
   display:inline; 
}

]]>
      </xh:style>
   </xh:head>
   <xh:body>
      <xf:group ref="rectangle">
         <!-- Height -->
         <xf:group ref="@height">
            <xf:label>Height: </xf:label>
            <!-- This should be displayed when the subform is not editing the height -->
            <xf:group ref=".[instance('dimension-interface')/@active!='height']">
               <xf:output ref="."/>
               <!-- Display the trigger when the subform is not loaded anywhere -->
               <xf:trigger ref=".[instance('dimension-interface')/@active = '']">
                  <xf:label>Edit</xf:label>
                  <xf:action ev:event="DOMActivate">
                     <!-- Set the value of the interface instance -->
                     <xf:setvalue ref="instance('dimension-interface')" value="instance('main')/rectangle/@height"/>
                     <!-- Remember that we are editing the height -->
                     <xf:setvalue ref="instance('dimension-interface')/@active">height</xf:setvalue>
                     <!-- Load the subform -->
                     <xf:load show="embed" targetid="height" resource="subform-embedded.xml"/>
                  </xf:action>
               </xf:trigger>
            </xf:group>
            <xh:span id="height"/>
            <!-- This should be displayed only when we're editing the height -->
            <xf:group ref=".[instance('dimension-interface')/@active='height']">
               <xf:trigger>
                  <xf:label>Done</xf:label>
                  <xf:action ev:event="DOMActivate">
                     <!-- Copy the value from the interface instance -->
                     <xf:setvalue value="instance('dimension-interface')" ref="instance('main')/rectangle/@height"/>
                     <!-- We're no longer editing any dimension -->
                     <xf:setvalue ref="instance('dimension-interface')/@active"/>
                     <!-- Unload the subform -->
                     <xf:unload targetid="height"/>
                  </xf:action>
               </xf:trigger>
            </xf:group>
         </xf:group>
         <br/>
         <!-- Width -->
         <xf:group ref="@width">
            <xf:label>Width: </xf:label>
            <xf:group ref=".[instance('dimension-interface')/@active!='width']">
               <xf:output ref="."/>
               <xf:trigger ref=".[instance('dimension-interface')/@active = '']">
                  <xf:label>Edit</xf:label>
                  <xf:action ev:event="DOMActivate">
                     <xf:setvalue ref="instance('dimension-interface')" value="instance('main')/rectangle/@width"/>
                     <xf:setvalue ref="instance('dimension-interface')/@active">width</xf:setvalue>
                     <xf:load show="embed" targetid="width" resource="subform-embedded.xml"/>
                  </xf:action>
               </xf:trigger>
            </xf:group>
            <xh:span id="width"/>
            <xf:group ref=".[instance('dimension-interface')/@active='width']">
               <xf:trigger>
                  <xf:label>Done</xf:label>
                  <xf:action ev:event="DOMActivate">
                     <xf:setvalue value="instance('dimension-interface')" ref="instance('main')/rectangle/@width"/>
                     <xf:setvalue ref="instance('dimension-interface')/@active"/>
                     <xf:unload targetid="width"/>
                  </xf:action>
               </xf:trigger>
            </xf:group>
         </xf:group>
      </xf:group>
   </xh:body>
</xh:html>

for the main form and:

<?xml-stylesheet href="xsltforms/xsltforms.xsl" type="text/xsl"?>
<?xsltforms-options debug="yes"?>
<xh:html xmlns:xh="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:ev="http://www.w3.org/2001/xml-events">
   <xh:head>
      <xh:title>A subform</xh:title>
      <xf:model id="subform-model">
         <xf:instance id="split">
            <height>
               <value/>
               <unit/>
            </height>
         </xf:instance>
         <xf:action ev:event="xforms-subform-ready">
            <xf:setvalue ref="instance('split')/value" value="translate(instance('dimension-interface'), '%incmptxe', '')"/>
            <xf:setvalue ref="instance('split')/unit" value="translate(instance('dimension-interface'), '0123456789', '')"/>
         </xf:action>
      </xf:model>
   </xh:head>
   <xh:body>
      <xf:group ref="instance('split')">
         <xf:input ref="value">
            <xf:label/>
            <xf:setvalue ev:event="xforms-value-changed" ref="instance('dimension-interface')" value="concat(instance('split')/value, instance('split')/unit)"/>
         </xf:input>
         <xf:select1 ref="unit">
            <xf:label/>
            <xf:setvalue ev:event="xforms-value-changed" ref="instance('dimension-interface')" value="concat(instance('split')/value, instance('split')/unit)"/>
            <xf:item>
               <xf:label>pixels</xf:label>
               <xf:value>px</xf:value>
            </xf:item>
            <xf:item>
               <xf:label>font size</xf:label>
               <xf:value>em</xf:value>
            </xf:item>
            <xf:item>
               <xf:label>font height</xf:label>
               <xf:value>ex</xf:value>
            </xf:item>
            <xf:item>
               <xf:label>inches</xf:label>
               <xf:value>in</xf:value>
            </xf:item>
            <xf:item>
               <xf:label>centimeters</xf:label>
               <xf:value>cm</xf:value>
            </xf:item>
            <xf:item>
               <xf:label>millimeters</xf:label>
               <xf:value>mm</xf:value>
            </xf:item>
            <xf:item>
               <xf:label>points</xf:label>
               <xf:value>pt</xf:value>
            </xf:item>
            <xf:item>
               <xf:label>picas</xf:label>
               <xf:value>pc</xf:value>
            </xf:item>
            <xf:item>
               <xf:label>%</xf:label>
               <xf:value>%</xf:value>
            </xf:item>
         </xf:select1>
      </xf:group>
   </xh:body>
</xh:html>

for the subform.

Acknowledging that things could be easier, XSLTForms has introduced a new experimental feature, derived from subforms, to implement simple components:

I have implemented a new component control in XSLTForms. It is named "xf:component” and has two attributes named “@ref” and “@resource“. There are still restrictions within a component: ids cannot be used if the component is to be instantiated more than once. The default instance is local to each instantiated component and the subform-instance() function can be used to get the document element of it. From the main form to the component, a binding with a special mip named “changed” is defined. The subform-context() allows to reference the node bound to the component control in the main form. The corresponding build has been committed to repositories: http://sourceforge.net/p/xsltforms/code/ci/master/tree/build/
Alain Couthures on the Xsltforms-support mailing list

With this new experimental feature and another extension (the @changed MIP implemented in XSLTForms), the master form would be:

<?xml-stylesheet href="xsltforms/xsltforms.xsl" type="text/xsl"?>
<?xsltforms-options debug="yes"?>
<xh:html xmlns:xh="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events"
   xmlns:xf="http://www.w3.org/2002/xforms">
   <xh:head>
      <xh:title>Subforms</xh:title>
      <xf:model>
         <xf:instance id="main">
            <figures>
               <rectangle height="10in" width="4em"/>
            </figures>
         </xf:instance>

      </xf:model>
   </xh:head>
   <xh:body>
      <xf:group ref="rectangle">
         <!-- Height -->
         <xf:group ref="@height">
            <xf:label>Height: </xf:label>
            <xf:component ref="." resource="component-subform.xml"/>
         </xf:group>
         <br/>
         <!-- Width -->
         <xf:group ref="@width">
            <xf:label>Width: </xf:label>
            <xf:component ref="." resource="component-subform.xml"/>
         </xf:group>
      </xf:group>
   </xh:body>
</xh:html>

and the subform (or component):

<?xml-stylesheet href="xsltforms/xsltforms.xsl" type="text/xsl"?>
<xh:html xmlns:xh="http://www.w3.org/1999/xhtml" 
    xmlns:xf="http://www.w3.org/2002/xforms" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:ev="http://www.w3.org/2001/xml-events">
    <xh:head>
        <xh:title>Size</xh:title>
        <xf:model>
            <xf:instance>
                <size>
                    <value xsi:type="xsd:decimal">2</value>
                    <unit>cm</unit>
                </size>
            </xf:instance>
            <xf:bind ref="subform-instance()/value" 
                changed="translate(subform-context(), '%incmptxe', '')"/>
            <xf:bind ref="subform-instance()/unit" 
                changed="translate(subform-context(), '0123456789', '')"/>
        </xf:model>
    </xh:head>
    <xh:body>
        <xf:input ref="subform-instance()/value">
            <xf:label/>
            <xf:setvalue ev:event="xforms-value-changed" 
                ref="subform-context()" value="concat(subform-instance()/value, 
                subform-instance()/unit)"/>
        </xf:input>
        <xf:select1 ref="subform-instance()/unit">
            <xf:label/>
            <xf:item>
                <xf:label>pixels</xf:label>
                <xf:value>px</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>font size</xf:label>
                <xf:value>em</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>font height</xf:label>
                <xf:value>ex</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>inches</xf:label>
                <xf:value>in</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>centimeters</xf:label>
                <xf:value>cm</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>millimeters</xf:label>
                <xf:value>mm</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>points</xf:label>
                <xf:value>pt</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>picas</xf:label>
                <xf:value>pc</xf:value>
            </xf:item>
            <xf:item>
                <xf:label>%</xf:label>
                <xf:value>%</xf:value>
            </xf:item>
            <xf:setvalue ev:event="xforms-value-changed" 
                ref="subform-context()" value="concat(subform-instance()/value, 
                subform-instance()/unit)"/>
        </xf:select1>
    </xh:body>
</xh:html>

The level of complexity of both the definition of the subform component and its invocation are similar to what we’ve seen with Orbeon’s XBL feature. The main difference is the encapsulation (no encapsulation in XSLTForms and a controlled encapsulation in Orbeon Forms which handles the issue of id collisions).

Note that we are escaping the issue caused by id collision because we are accessing the instance from the master form directly from the subform using the subform-context() function.

This feature allows us to use only one local instance in the subform and we take care of not defining any id for this instance and access it using the subform-instance() function.
This trick wouldn’t work if we needed several instances or if we had to define ids on other elements in the subform.

Conclusion

The lack of modularity has been one of the serious weaknesses in the XForms recommendations so far.

A common solution is to generate or “template” XForms but this can be tricky when dealing with “components” used multiple times in a form and especially within xf:repeat controls.

Different implementation have come up with different solutions to address this issue (XBL for Orbeon, subforms for betterFORM and XSLTForms).

The main differences between these solutions are:

  • The syntax:
    • XBL + XForms for Orbeon Forms
    • XForms with minor extensions for betterFORM and XSLTForms)
  • The encapsulation or isolation and features to communicate between the component and other models:
    • complete for betterFORM with extensions to communicate between models
    • either complete or partial for Orbeon Forms with extension to communicate between models
    • no isolation for XSLTForms with extensions to access to the context node and default instance from a component
  • The support of id collisions between components and the main form:
    • Id collisions are handled by Orbeon Forms
    • They are forbidden by betterFORM and XSLTForms

The lack of interoperability between these implementations will probably not be addressed by the W3C XForms Working Group and it would be very useful if XForms implementers could work together to define interoperable solutions to define reusable components in XForms.

In this paper, generation (or templating) has been presented as an alternative to XML or subforms but they are by no mean exclusive. In real world projects, hybrid approaches mixing XForms generation (or templating) and components (XBL or subforms) are on the contrary very valuable. They have been demonstrated in a number of talks during the pre-conference day at XML Prague.

These hybrid approaches are easy to implement with common XML toolkits. The generation/templating can be static (using tools such as XProc, Ant or classical make files) or dynamic (using XProc or XPL pipelines or plain XQuery or XSLT) and Orbeon Forms XBL implementation even provides a feature to dynamically invoke a transformation on the content of the bound element).

Acknowledgments

I would like to thank Erik Bruchez (Orbeon), Joern Turner (betterFORM) and Alain Couthures (XSLTForms) for the time they’ve spent to answer my questions and review this paper.

Share and Enjoy:
  • Identi.ca
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Add to favorites

When MVC becomes a burden for XForms

XForms describes itself as a MVC architecture:

An XForm allows processing of data to occur using three mechanisms:

  • a declarative model composed of formulae for data calculations and constraints, data type and other property declarations, and data submission parameters
  • a view layer composed of intent-based user interface controls
  • an imperative controller for orchestrating data manipulations, interactions between the model and view layers, and data submissions.

Micah Dubinko argues that the mapping is more obvious with Model-view-presenter (MVP), a derivative of the MVC software pattern but that’s not the point I’d like to make and I’ll stick to the MVC terminology where:

  • The model is composed of XForms instances and binds
  • The view is composed of the XForms controls together with the HTML elements and CSS stylesheets
  • The controller is composed of the actions
Mode-view-controler on wikimedia
Mode-view-controler on wikimedia

Orbeon Form Builder goes one step forward and adds a fourth concern for localization and we get a model/view/localization/controller pattern.

This separation of concerns is great to differentiate different roles and split work between specialists but doesn’t play well with modularity and reusability.

I am currently working on a project to develop big and complex forms and this is becoming one of the biggest issues: these forms share a number of common fields and group of fields and, not even speaking of sharing these definitions, this separation of concerns adds a significant burden when copying these definitions from one form to another.

To copy a field from one form to another you need to copy definitions from the model, the view, the localization and the controller and can’t just copy a “component”.

And of course, there is no easy way to reuse common components instead of copying them.

I am not the first to question this issue with MVC and the Hierarchical model–view–controller (HMVC) has been introduced for this purpose, but how can we use such a pattern with XForms?

Hierarchical model-view-controller in JavaWorld
Hierarchical model-view-controller in JavaWorld

In fact, I m wondering if some of the innovative ways to develop XForms application which have been presented during the XML Prague 2013 pre-conference day were not more or less ways to deal with this issue.

For Orbeon Forms the way to deal with reusability issues is through XBL components.

XBL components cleanly encapsulate their own model/view/controller concerns but their development is highly technical and can’t be defined using Form Builder: you can use XBL components in Form Builder but you have to create them by hand and there is no way to just say “I want to define this group of fields as a new XBL component and use this component in other forms”. Such a feature would be most useful!

Another way to deal with this issue is to use a meta model and generate XForms. I am involved in another project which is following this path and you can expect to hear more about it in these pages!

Share and Enjoy:
  • Identi.ca
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Add to favorites

HTML 5 turns documents into applications

 Voir aussi la version française de cet article sur XMLfr.

HTML 5 is not just HTML 4 + 1

This announcement has been already widely commented and I won’t come back on the detail of the differences between HTML 4.1 and HTML 5 which are detailed in one of the documents published with the Working Draft. What I find unfortunate is that this document and much of the comments about HTML 5 focus on the detail of the syntactical differences between these versions rather than commenting more major differences.

These differences are clearly visible as soon as you read the introduction:

The World Wide Web’s markup language has always been HTML. HTML was primarily designed as a language for semantically describing scientific documents, although its general design and adaptations over the years has enabled it to be used to describe a number of other types of documents.

The main area that has not been adequately addressed by HTML is a vague subject referred to as Web Applications. This specification attempts to rectify this, while at the same time updating the HTML specifications to address issues raised in the past few years.

This introduction does a good job in setting the context and expectations: the goal of HTML 5 is to move from documents to applications and this is confirmed in many other places, such as for instance the section titled “Relationship to XUL, Flash, Silverlight, and other proprietary UI languages”:

This specification is independent of the various proprietary UI languages that various vendors provide. As an open, vender-neutral language, HTML provides for a solution to the same problems without the risk of vendor lock-in.

To understand this bold move, we need to set this back into context.

Nobody denies that HTML has been created to represent documents, but its success comes from its neutrality: even if it is fair to say that Web 2.0 is the web has it was meant to be, the makers of HTML couldn’t imagine everything that can be done in modern web applications. If these applications are possible in HTML, this is because HTML has been designed to be neutral enough to describe yesterday’s, today’s and probably tomorrow’s applications.

If on the contrary, HTML 4.01 had attempted to describe, in 1999, what was a web application, it is pretty obvious that this description would have had to be in the best case worked around and that it might even have slowed down the development of Web 2.0.

This is the reason why I would make to HTML 5 the same kind of criticism I made to W3C XML Schema: over specifying how to use a document is a risk to block creativity and increase the coupling between applications.

While many people agree that web applications should be designed as documents, HTML 5 appears to propose to move from documents to applications. This seems to me to be a major step… backward!

Flashback on HTML’s history

Another point that needs to be highlighted are the relations between HTML 5 and XML in general and XHTML in particular.

HTML 5 presents itself as the sibling of both HTML 4.01 and XHTML 1.1 and as a competitor of XHTML 2.0.

To understand why the W3C is developing two competing standards, we need a brief reminder of the history of HTML.

HTML has been originally designed as a SGML vocabulary and uses some of its features to reduce the verbosity of its documents. This is the case for instance of tags such as <img> or <link> that do not need to be closed in HTML.

XML has been designed to be a simplification of SGML and this simplification does not allow to use the features used by HTML to reduce its verbosity.

When XML has been published, W3C found themselves with a SGML application in one hand (HTML) and a simplification of SGML in the other hand (XML) and these two recommendations were incompatible.

To make these recommendations compatible, they decided to create XHTML 1.0 which is a revamping of HTML to be compatible with the XML recommendation while keeping th exact same features. This lead to XHTML 1.0 and then XHTML 1.1 which is roughly the same thing cut into modules that can be used independently.

One of the weaknesses of HTML being its forms, W3C did also work on XForms, a new generation of web forms and started to move forward working on a new version of XHTML with new features, XHTML 2.0 still work in progress.

The approach looked so obvious that W3C has probably neglected to check that the community was still following its works. With the euphoria that followed the publication of XML 1.0 many people were convinced that the browsers war was over, the interest for HTML which was partly fueled by this war started to decline and the W3C works in this domain didn’t seem to raise that much interest compared to let’s say XML Schema languages or Web Services.

It is also fair to say that the practical interest to move from HTML to XHTML wasn’t (and still isn’t) obvious for web site developers since the features are the same. Migrating a site from HTML to XHTML involves an additional work which is only compensated by the joy of displaying a “W3C XHTML 1.x compliant” logo!

This is also the moment when Microsoft stopped any development on Internet Explorer and Netscape transferred their development to Mozilla.

The old actors from the browsers war, well represented at the W3C which was one of their battle fields led the way to new actors, Mozilla, Opera and Apple/Safari younger and less keen to accept the heaviness of W3C procedures.

At the same time, the first Web 2.0 applications sparkled a new wave of creativity among web developers and all this happened outside the W3C. This is not necessarily a bad thing since the mission of standard bodies such as W3C is to standardize rather than innovate, but the W3C doesn’t appear to have correctly estimated the importance of these changes and seems to have lost the contact with their users.

And when these users, led by Opera, Mozilla and Safari decided that it was time to move HTML forward, rather than jump into the XHTML 2.0 wagon, they decided to create their own Working Group, WHATWG, outside the W3C. This is where the first versions of HTML 5 have been drafted together with Web Forms 2.0, a sister documentation designed to be an enhancement of HTML forms simpler than Xforms.

Microsoft was still silent on this subject and the W3C saw themselves as editor of a promising new specification, XHTML 2.0 which didn’t seem to attract much attention while, outside, a new specification claiming to be the true successor of HTML was being developed by the most promising outsiders in the browser market.

At XTech 2007, I had a chance to measure the depth of the channel that separates the two communities by attending to a debate between both working groups.

Tim Berners-Lee must have found that this channel was too deep when he took the decision to invite the WHATWG to continue their work within the W3C in a Working Group created for this purpose and distinct from the XHTML 2.0 Working Group that continues their work as if nothing has changed.

HTML 5 or XHTML 2.0?

So, the W3C has now two distinct and competing Working Groups.

Missons are very close

The XHTML 2.0 Working Group develops an extensible vocabulary based on XML:

The mission of the XHTML2 Working Group is to fulfill the promise of XML for applying XHTML to a wide variety of platforms with proper attention paid to internationalization, accessibility, device-independence, usability and document structuring. The group will provide an essential piece for supporting rich Web content that combines XHTML with other W3C work on areas such as math, scalable vector graphics, synchronized multimedia, and forms, in cooperation with other Working Groups.

The HTML Working Group focuses on the continuity with previous HTML versions:

The mission of the HTML Working Group, part of the HTML Activity, is to continue the evolution of HTML (including classic HTML and XML syntaxes).

The conciseness of this sentence doesn’t imply that the HTML Working Group isn’t worried about extensibility and cross platform support since the list of deliverables says “there is a single specification deliverable for the HTML Working Group, the HTML specification, a platform-neutral and device-independent design”and later on “the HTML WG is encouraged to provide a mechanism to permit independently developed vocabularies such as Internationalization Tag Set (ITS), Ruby, and RDFa to be mixed into HTML documents”.

The policy is thus clearly, taking the risk to see a standards war develop, to develop two specifications and let user choose.

XHTML 5 is a weak alibi

We find this policy within the HTML 5 specification that proposes to choose between two syntaxes:

This specification defines an abstract language for describing documents and applications, and some APIs for interacting with in-memory representations of resources that use this language.

The in-memory representation is known as “DOM5 HTML”, or “the DOM” for short.

There are various concrete syntaxes that can be used to transmit resources that use this abstract language, two of which are defined in this specification.

The first such concrete syntax is “HTML5”. This is the format recommended for most authors. It is compatible with all legacy Web browsers. If a document is transmitted with the MIME type text/html, then it will be processed as an “HTML5” document by Web browsers.

The second concrete syntax uses XML, and is known as “XHTML5”. When a document is transmitted with an XML MIME type, such as application/xhtml+xml, then it is processed by an XML processor by Web browsers, and treated as an “XHTML5” document. Authors are reminded that the processing for XML and HTML differs; in particular, even minor syntax errors will prevent an XML document from being rendered fully, whereas they would be ignored in the “HTML5” syntax.

This section, which by chance is non-normative, appears to exclude that a browser might accept any other HTML document than HTML5 or any XHTML other than XHTML5!

Furthermore, with such a notice, I wonder who would want to choose XHTML 5 over HTML5…

This notice relies on a frequent misunderstanding of the XML recommendation. It is often said that XML parsing must stop after the first error, but the recommendation is much more flexible than that and distinguishes two types of errors:

  • An error is “a violation of the rules of this specification; results are undefined. Unless otherwise specified, failure to observe a prescription of this specification indicated by one of the keywords MUST, REQUIRED, MUST NOT, SHALL and SHALL NOT is an error. Conforming software MAY detect and report an error and MAY recover from it.”
  • A fatal errors is “an error which a conforming XML processor MUST detect and report to the application. After encountering a fatal error, the processor MAY continue processing the data to search for further errors and MAY report such errors to the application. In order to support correction of errors, the processor MAY make unprocessed data from the document (with intermingled character data and markup) available to the application. Once a fatal error is detected, however, the processor MUST NOT continue normal processing (i.e., it MUST NOT continue to pass character data and information about the document’s logical structure to the application in the normal way).”

We see that on the contrary, the XML recommendation specifies that a XML processor can correct simple errors.

One may argue that what XML considers as a fatal error can be considered by users as simple errors, this would be the case for instance of a <img> tag that wouldn’t be closed. But even for fatal errors, the recommendation doesn’t stipulate that the browser should not display the document. It does require that the parser report the error to the browser but doesn’t say anything about how the browser should react. Similarly, the recommendation imposes that normal processing should stop because the parser would be unable to reliability report the structure of the document but doesn’t say that the browser shouldn’t switch to a recovery mode where it could try to correct this error.

In fact, if browsers are so strict when they display XML documents, this isn’t to be conform to the XML recommendation but because there was a consensus that they should be strict at the time when they implemented their XML support.

At that time, everyone had in mind the consequence of the browsers war that was one of the reasons why browsers accepted pretty much anything that pretended to be HTML. While this can be considered a good thing in some cases, this also means implementing a lot of undocumented algorithms and this leads to major interoperability issues.

The decision to be strict when displaying XML documents came as a new era good resolution and nobody seemed to dissent at that time.

If this position needs to be revisited, it would be ridiculous to throw away XML since we have seen that it isn’t imposed by the recommendation.

The whole way in which the two HTML5 syntaxes are presented is a clear indication thet the XML syntax which was not mentioned in the first HTML5 drafts has been added as a compromise so that the W3C doesn’t look like if they rejected XML, but that the idea is to maintain and promote a non XML syntax.

HTML 5 gets rid of its SGML roots

Not only does HTML 5 rejects XML, but it also abandons any kind of compatibility with SGML and says clearly “while the HTML form of HTML5 bears a close resemblance to SGML and XML, it is a separate language with its own parsing rules”.

This sentence is symptomatic of the overall attitude of the specification that seems to pretend to build on the experience of the web and ignore the experience of markup languages, taking the risk once again, to freeze the web to its current status.

The attitude of the XHTML Working Group is better balanced. Of course, XHTML 2.0 is about building on the most recent web development, but it doesn’t do so without keeping the experience acquired while developing XML and SGML vocabularies.

Technical approaches radically different

Without entering into a detailed comparison, two points are worth mentioning.

XHTML 2.0 is more extensible

Both specifications acknowledge the need to take into account the requirements that have appeared since HTML has been created when these are not correctly supported, but the method to do so is totally different.

HTML 5 has adopted a method that looks simple: if a new need is considered important enough, a new element is added. Since many pages contain articles, a new <article> element is added. And since most pages have navigation bars, a new <nav> element is added…

We have seen with the big vocabularies in document applications what are the limits of this approach: this leads to an explosion of the number of elements and the simplicity turns into complexity. It becomes difficult to choose between elements and pick the right one and since these elements are specialized, they never meet exactly your needs

Using this approach with HTML is more or less a way to transform it into a kind of DocBook clone for the web in the long term.

XHTML 2.0 has taken an opposite approach. The idea is, on the contrary, to start with a clean up and remove any element from XHTML that isn’t absolutely necessary.

It relies then on current practices: how do we do to represent an article or a navigation bar? The most common approach is to use a standard element, often a <div> and hijack the class attribute to apply a CSS style or a JavaScript animation.

The downside is that the values of the class attribute aren’t standardised and that the class attribute is used to convey information about the meaning of an element rather than define the way it should be displayed. This kind of hijack is pretty common since this is also the foundation of microformats.

To avoid this hijack while keeping the flexibility if this approach, XHTML 2.0 proposes to add a role attribute that defines the role of XHTML elements. This attribute can take a set of predefined values together with ad hoc values differentiated by their namespaces.

This method is a way to introduce the same kind of features that will be added to HTML 5 without adding new elements. This is more flexible since anyone can create new values in new namespaces. This also gives microformats a way to build upon something more solid than the class attribute that can be used again to define how elements should be presented.

Documents versus applications

Another important point that differentiate these two specification is their balance between data and applications or treatments.

XHTML 2.0 is built upon the XML stack:

  • The lower level is syntactical and consists of the XML and namespaces recommendations.
  • On top of this layer, the XML infoset defines a data model independent of any kind of treatment.
  • APIs, specific languages (XPath, XQuery, …) and schema languages are built on to of this data model.

It took some few years to build this architecture and things haven’t always been that clear and simple, but its big benefit is to separate data and treatments and be just the right one for a weak coupling between applications.

We’ve seen that HTML 5 has cut all its links to XML and SGML and that means that it doesn’t rely on this architecture. On the contrary, this specification mixes everything, syntax, data model and API (DOM) in a single specification.

This is because, as we’ve already seen, HTML 5 is a vocabulary to develop web applications rather than a vocabulary to write documents.

The difference seems important to me in not only in term of architecture but also in term of sustainability. Everyone agrees that XML is one of the best formats for long term preservation of documents. What is true of documents is probably not true of applications and I don’t think a HTML 5 application with a good proportion of JavaScript will be as sustainable as a XHTML 2.0 document.

The architecture on which XHTML 2.0 is built doesn’t prevent people from developing applications, but it dissociates more clearly these applications from the content.

Furthermore, XHTML 2.0 is also trying to develop and promote declarative alternatives such as XForms to define web applications that should be a better fit than JavaScript for documents.

Will the best specification win?

For all these reasons, HTML 5 looks to me as a big step backward and XHTML 2.0 seems to be a much better alternative.

Does that mean that XHTML 2.0 will be the winner or on the contrary, does the fact that HTML 5 is written by those who develop web browsers mean that XHTML 2.0 is doomed?

XHTML 2.0 has a strong handicap, but the battle isn’t lost yet. The HTML Working Group doesn’t expect that HTML 5 becomes a recommendation before Q3 20010 and before that date everything can happen.

It is up to us, the users, to vote with our feet and pen and start by boycotting the HTML 5 features that are already implemented in some browsers.

And short term, certifying that a page us XHTML 1.x valid is a good way to certify that it doesn’t contain HTML 5 features!

Share and Enjoy:
  • Identi.ca
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Add to favorites