XForms


XForms

Elliotte Rusty Harold

Software Devlopment 2005 West

Thursday, March 17, 2005

elharo@metalab.unc.edu

http://www.cafeconleche.org/


Some Opinions

XForms, a combination of two of the most successful experiments ever performed with the Web: XML and forms.

--Micah Dubinko


For my current contract they could have saved months of effort by using XForms instead of standard HTML forms. We're talking thousands and thousands of lines of JSP code that could be thrown in the trash. I love nothing more than throwing code away ... love it.

--Kimbro Staken


It's not surprising that XForms is raising hackles and ruffling feathers since it has the potential to displace a language that a lot of people have spent a lot of time learning and building businesses around. But just as I gave up assembler programming to use C, so I now gladly drop spaghetti-script for XForms. It's not perfect and there are plenty of new features that I would like to see introduced, but its most important role has been to demonstrate that we don't need to be wedded to the old approaches for ever, and that new solutions are possible, and here today.

--Mark Birbeck


And a contrarian view:

I personally like XForms. However, I think it is a lost cause on the popular Web for three reasons:

  1. It's not backwards compatible with existing Web content and existing Web browsers,

  2. It uses too many levels of abstraction to be understood by most authors.

  3. It requires the use of many namespace prefixes.

None of these problems really have anything to do with XForms features per se. It is IMHO possible to bring many of XForms features (especially the declarative constraints ideas) to authors without introducing the other problems. For instance, by just extending HTML's form features instead of making a totally new language.

--Ian Hickson, Opera


What's Wrong with HTML Forms?


Scripting Issues


What's Right with HTML Forms?


What does XForms Give You?


Some Demos in X-Smiles


XForms are being used in


Model-View-Controller

An XForm has three parts:


A Very Simple Form





A Model for the Very Simple Form


A View for the Very Simple Form


A Controller for the Very Simple Form

Load the simple form in a browser

The complete doughnut order document

<?xml version="1.0"?>
<!-- <!DOCTYPE html 
     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "xhtml1-strict.dtd"> -->
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:xf="http://www.w3.org/2002/xforms"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
  <head>
    <title>Doughnuts!</title>
    <model xmlns="http://www.w3.org/2002/xforms" id="p1">
    <instance>
       <doughnuts xmlns="">
        <quantity xsi:type="xsd:nonNegativeInteger"/>
       </doughnuts>
    </instance>
    <submission action="http://sinex.tml.hut.fi:8080/xforms/request"
      method="post" id="q0" />
    </model>
  </head>
  <body>
    <h1>Order Doughnuts</h1>
  
  <input xmlns="http://www.w3.org/2002/xforms"
    xmlns:ev="http://www.w3.org/2001/xml-events"
    model="p1" 
    ref="/doughnuts/quantity" 
    class="edit" >
    <label>Quantity</label>
  </input>
  
  <p>
    I can put any XHTML markup and text here I like.
    The form can be interspersed throughout the page. 
    Namespaces are used to tell which elements are XHTML
    and which are XForms.
  </p>
  
  <submit xmlns="http://www.w3.org/2002/xforms" submission="q0">
    <label>Order</label>
  </submit>
  
  </body>
</html>

Accepting the Data on the Server Side


Controlling serialization


replace="instance"


External Schema


Default Values


XForms Abstract User Interface Controls


Control attributes

Certain common attributes apply to all controls:

<forms:input 
  id="state_shipping" 
  class="data_entry" 
  ref="order/shipTo/state" 
  cols="4" 
  model="shipping"
  style="font-family: Helvetica, sans"
  appearance="compact">
    <forms:label>State:</forms:label>
</forms:input>

Control interaction attributes

<forms:input 
  accesskey="r" 
  navindex="3" 
  incremental="false"
  inputmode="upperCase">
    <forms:label>State:</forms:label>
</forms:input>

Control Child Elements


textarea

<textarea ref="message/body">
  <label>Message Body</label>
  <hint>Enter the text of your message here</hint>
</textarea>

select

<select ref="pz:toppings">
  <label>Flavors</label>
  <choices>
    <item>
      <label>Pepperoni</label>
      <value>pprn</value>
    </item>
    <item>
      <label>Ham</label>
      <value>ham</value>
    </item>
    <item>
      <label>Pineapple</label>
      <value>pnnp</value>
    </item>
    <item>
      <label>Anchovies</label>
      <value>anch</value>
    </item>
    <item>
      <label>Garlic</label>
      <value>garl</value>
    </item>
    <item>
      <label>Sausage</label>
      <value>ssge</value>
    </item>
  </choices>
</select>

select1

<select1 ref="cc:type">
  <label>Credit Card</label>
  <item>
    <label>American Express</label>
    <value>amex</value>
  </item>
  <item>
    <label>Visa</label>
    <value>visa</value>
  </item>
  <item>
    <label>Mastercard</label>
    <value>mc</value>
  </item>
</select1>

Open selections

<select ref="pz:toppings" selection="open">
  <label>Flavors</label>
  <choices>
    <item>
      <label>Pepperoni</label>
      <value>pprn</value>
    </item>
    <item>
      <label>Ham</label>
      <value>ham</value>
    </item>
    <item>
      <label>Pineapple</label>
      <value>pnnp</value>
    </item>
    <item>
      <label>Anchovies</label>
      <value>anch</value>
    </item>
    <item>
      <label>Garlic</label>
      <value>garl</value>
    </item>
    <item>
      <label>Sausage</label>
      <value>ssge</value>
    </item>
  </choices>
</select>

Give Feedback example from X-Smiles

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="forms.xsl"?>
<form xmlns:xfm="http://www.w3.org/2001/11/xforms-editors-copy" height="30cm">

  <xfm:model id="form1">
  <xfm:submission id="submit1" method="postxml" 
    target="http://localhost:8080/examples/servlet/XFormsServlet"/>
    <xfm:schema src="simple1.xsd"/>
    <xfm:instance id="instance1" xmlns="">
      <?xml2-stylesheet type="text/xsl" href="../demo/fo/submit.xsl"?>
      <purchaseOrder>
        <shipTo>
          <firstname></firstname>
          <lastname></lastname>
          <email></email>
          <organization></organization>
          <subject></subject>
          <comment></comment>
        </shipTo>
        <itemlist>xsmiles_personal xsmiles_support</itemlist>
      </purchaseOrder>
    </xfm:instance>
  </xfm:model>
  
  <h1>X-Smiles Feedback</h1>
  
  <xfm:input xform="form1" ref="purchaseOrder/shipTo/firstname" cols="30">
    <xfm:label>FIRST NAME:</xfm:label>
  </xfm:input>
  
  <xfm:input ref="purchaseOrder/shipTo/lastname" cols="30">
    <xfm:label>LAST NAME:</xfm:label>
  </xfm:input>
  
  <xfm:input xform="form1" ref="purchaseOrder/shipTo/email" cols="30">
    <xfm:label>EMAIL:</xfm:label>
  </xfm:input>
  
  <xfm:input xform="form1" ref="purchaseOrder/shipTo/organization" cols="30">
    <xfm:label>ORGANIZATION:</xfm:label>
  </xfm:input>
  
  <xfm:select1 xform="form1" ref="purchaseOrder/shipTo/subject" 
    style="list-ui:radio;hip:hop">
    <xfm:hint>Please select one</xfm:hint>
    <xfm:label>SUBJECT:</xfm:label>
    <xfm:item>Compliment</xfm:item>
    <xfm:item>Opinion</xfm:item>
    <xfm:item>Criticism</xfm:item>
    <xfm:item>Suggestion</xfm:item>
    <xfm:item>Error</xfm:item>
  </xfm:select1>
  
  <xfm:textarea xform="form1" ref="purchaseOrder/shipTo/comment" rows="5" 
    style="font-size:10px; font-weight:bold; color:red; width:200px; height:70px;">
      <xfm:label>Please enter your comments in the area below:</xfm:label>
  </xfm:textarea>
  
  <xfm:submit name="Submit" ref="test" submission="submit1">
    <xfm:hint>Click to submit</xfm:hint>
    <xfm:label>Submit</xfm:label>
  </xfm:submit>
  
</form>

    

secret

<secret ref="/userinfo/password">
  <label>Password</label>
  <hint>Mother's maiden name</hint>
</secret>

upload

<upload ref="patch" mediatype="text/*">
  <label>Select image:</label>
  <filename ref="@name" />
  <mediatype ref="@mimetype" />
</upload>

range

<range ref="/settings/volume" start="1" end="11" step="0.1">
  <label>Volume</label>
  <hint>These go to 11.</hint>
</range>

output

Total: <output ref="order/total" />

Tax: <output value="0.825 * order/total" />


Datatype Aware Controls example from X-Smiles


<?xml version="1.0" encoding="ISO-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:xfm="http://www.w3.org/2002/xforms" 
      xml:lang="fi">
<meta:meta xmlns:meta="http://www.xsmiles.org/2002/metadata" 
           name="Datatype-Aware Controls" 
           description="Tests datatype awareness of XForms implementation" />
  <head>
    <style type="text/css">
      body {
        background-color: #dddddd;  
      }
      input,output,range {display:block;}
      input::value {
        width: 200px;
        font-weight:bold;
      }
      output::value {
        width: 200px;
        font-weight:bold;
        color:blue;
        background-color: #dddddd;
      }
      label
      {
        color:black;
      }
    </style>
            <link rel="stylesheet" type="text/css" href="../xforms.css" />
        
    <xfm:model id="form1" schema="simple.xsd">
    <xfm:submission id="submit1" method2="postxml" localfile="temp2.xml" 
                    target2="http://www.hut.fi/"/>
    <xfm:instance id="instance1" xmlns="">
      <?xml2-stylesheet type="text/xsl" href="../demo/fo/submit.xsl"?>
      <purchaseOrder>
        <shipTo>
          <volume>2</volume>
          <name>Alice Smith</name>
          <street>123 Maple Street</street>
          <city type="ao">Mill Valley</city>
          <state>CA</state>
          <zip>16</zip>
          <shipped>false</shipped>
          <selection>Ghana</selection>
          <static>
            <data>333</data>
          </static>
          <text>Original</text>
          <date>2002-10-23</date>
        </shipTo>
        <itemlist>xsmiles_personal xsmiles_support</itemlist>
      </purchaseOrder>
    </xfm:instance>
  </xfm:model>
  </head>
  <body>
  <h1>Adaptive inputs</h1>
<p>The inputs in this page adapt to the datatype of the bound instance
item. (Note that there are 2 inputs per item, to show that data flows
in/out between the controls and the instance.</p>

  <h2>&lt;input&gt;</h2>
  <p>
  <xfm:input model="form1" ref="shipTo/street" 
             incremental="true" inputmode="test">
    <xfm:label>xsd:string</xfm:label>
    <xfm:hint>This should be plain text textfield.</xfm:hint>
  </xfm:input>
  <xfm:input model="form1" ref="shipTo/street" 
             incremental="false" inputmode="test">
    <xfm:label>xsd:string</xfm:label>
    <xfm:hint>This should be plain text textfield.</xfm:hint>
  </xfm:input>
  </p>
  
  <p>
  <xfm:input model="form1" ref="shipTo/date" >
    <xfm:label>xsd:date</xfm:label>
    <xfm:hint>This should be a calendar control.</xfm:hint>
  </xfm:input>
  <xfm:input model="form1" ref="shipTo/date" >
    <xfm:label>Ship By:</xfm:label>
    <xfm:hint>This should be a calendar control.</xfm:hint>
  </xfm:input>
  </p>

  <p>
  <xfm:input model="form1" ref="shipTo/shipped">
    <xfm:label>xsd:boolean</xfm:label>
    <xfm:hint>This should be checkbox.</xfm:hint>
  </xfm:input>
  <xfm:input model="form1" ref="shipTo/shipped">
    <xfm:label>Are you married?</xfm:label>
    <xfm:hint>This should be checkbox.</xfm:hint>
  </xfm:input>
  </p>

  <p>
  <xfm:input model="form1" ref="shipTo/zip">
    <xfm:label>xsd:decimal</xfm:label>
    <xfm:hint>This should be decimal inputbox.</xfm:hint>
  </xfm:input>
  <xfm:input model="form1" ref="shipTo/zip">
    <xfm:label>xsd:decimal</xfm:label>
    <xfm:hint>This should be decimal inputbox.</xfm:hint>
  </xfm:input>
  </p>

  <h2>&lt;range&gt;</h2>
  <p>
  <xfm:range model="form1" ref="shipTo/zip" start="-1.5" end="20.5" step="1.5">
    <xfm:label>xsd:decimal</xfm:label>
    <xfm:hint>This should be a slider.</xfm:hint>
  </xfm:range>
  <xfm:range model="form1" ref="shipTo/zip" start="4.0">
    <xfm:label>xsd:decimal</xfm:label>
    <xfm:hint>This should be a slider.</xfm:hint>
  </xfm:range>
  </p>


  <h2>&lt;output&gt;</h2>

  <xfm:output model="form1" ref="shipTo/street"
              incremental="true" inputmode="test">
    <xfm:label>xsd:string</xfm:label>
    <xfm:hint>This should be an output string.</xfm:hint>
  </xfm:output>
  <xfm:output model="form1" ref="shipTo/date" >
    <xfm:label>xsd:date</xfm:label>
    <xfm:hint>This should be an output string.</xfm:hint>
  </xfm:output>
  <xfm:output model="form1" ref="shipTo/shipped">
    <xfm:label>xsd:boolean</xfm:label>
    <xfm:hint>This should be an output string.</xfm:hint>
  </xfm:output>
  <xfm:output model="form1" ref="shipTo/zip">
    <xfm:label>xsd:decimal</xfm:label>
    <xfm:hint>This should be an output string.</xfm:hint>
  </xfm:output>
  <xfm:submit name="Submit" submission="submit1">
    <xfm:hint>Click to submit</xfm:hint>
    <xfm:label>Submit</xfm:label>
  </xfm:submit> 
  
  </body>
</html>

XForms Controls example from X-Smiles

<?xml version="1.0" encoding="ISO-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml" 
  xmlns:xforms="http://www.w3.org/2002/xforms" 
  xmlns:ev="http://www.w3.org/2001/xml-events" 
  xmlns:my="test" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <meta:meta 
    xmlns:meta="http://www.xsmiles.org/2002/metadata" 
    name="XForms Controls" 
    description="Tests all XForms controls in single document" />

  <head>
    <link rel="stylesheet" type="text/css" href="xforms.css" />
    <xforms:model id="form1">
      <xforms:submission id="submit1" method="post" 
         action="http://sinex.hut.mediapoli.com:8080/xforms/request"/>
      <xforms:instance id="instance1" xmlns="" >
        <my>
          <input>Initial input</input>
          <secret>Initial secret</secret>
          <output>Initial output</output>
          <textarea>Initial textarea</textarea>
          <range>5</range>
          <select1>1</select1>
          <select>1</select>
          <selectboolean>true</selectboolean>
          <message>Message read from the instance</message>
          <upload xsi:type="xsd:base64Binary"/>
        </my>
      </xforms:instance>
      <xforms:bind nodeset="/my/selectboolean" type="xsd:boolean"/>
    </xforms:model>
  </head>
<body>
<p>
<h1>All XForms form controls</h1>
<p class="headline">&lt;textarea&gt;</p>
<xforms:textarea ref="/my/textarea">
  <xforms:label>Textarea Form Control</xforms:label>
</xforms:textarea>
<xforms:textarea ref="/my/textarea">
  <xforms:label>Textarea Form Control</xforms:label>
</xforms:textarea>

<p class="headline">&lt;input&gt;</p>
<p>
<xforms:input ref="/my/input" xmlns:my="test">
  <xforms:label>Input Form Control</xforms:label>
</xforms:input>
</p>
<p class="headline">&lt;output&gt;</p>
<xforms:output ref="/my/output" xmlns:my="test">
  <xforms:label>Input Form Control</xforms:label>
</xforms:output>
    <p class="headline">&lt;secret&gt;</p>
    <xforms:secret ref="/my/secret">
  <xforms:label>Secret Form Control</xforms:label>
</xforms:secret>


<p class="headline">&lt;upload&gt;</p>
<xforms:upload ref="/my/upload">
  <xforms:label>Select File</xforms:label>
</xforms:upload>
    <p class="headline">&lt;select1&gt;</p>
    <p>
    <xforms:select1 ref="/my/select1" appearance="full">
  <xforms:label>appearance="full"</xforms:label>
  <xforms:item>
    <xforms:value>1</xforms:value>
    <xforms:label>1st</xforms:label>
  </xforms:item>
  <xforms:item>
    <xforms:value>2</xforms:value>
    <xforms:label>2nd</xforms:label>
  </xforms:item>
  <xforms:item>
    <xforms:value>3</xforms:value>
    <xforms:label>3rd</xforms:label>
  </xforms:item>
</xforms:select1>

<xforms:select1 ref="/my/select1" appearance="compact">
  <xforms:label>appearance="compact"</xforms:label>
  <xforms:item>
    <xforms:label>1st</xforms:label>
    <xforms:value>1</xforms:value>
  </xforms:item>
  <xforms:item>
    <xforms:label>2nd</xforms:label>
    <xforms:value>2</xforms:value>
  </xforms:item>
  <xforms:item>
    <xforms:label>3rd</xforms:label>
    <xforms:value>3</xforms:value>
  </xforms:item>
</xforms:select1>

<xforms:select1 ref="/my/select1" appearance="full">
  <xforms:label>appearance="full"</xforms:label>
  <xforms:item>
    <xforms:label>1st</xforms:label>
    <xforms:value>1</xforms:value>
  </xforms:item>
  <xforms:item>
    <xforms:label>2nd</xforms:label>
    <xforms:value>2</xforms:value>
  </xforms:item>
  <xforms:item>
    <xforms:label>3rd</xforms:label>
    <xforms:value>3</xforms:value>
  </xforms:item>
</xforms:select1>

<xforms:select1 ref="/my/select1" appearance="minimal">
  <xforms:label>appearance="minimal"</xforms:label>
  <xforms:item>
    <xforms:label>1st</xforms:label>
    <xforms:value>1</xforms:value>
  </xforms:item>
  <xforms:item>
    <xforms:label>2nd</xforms:label>
    <xforms:value>2</xforms:value>
  </xforms:item>
  <xforms:item>
    <xforms:label>3rd</xforms:label>
    <xforms:value>3</xforms:value>
  </xforms:item>
</xforms:select1>
</p>
<p class="headline">&lt;select&gt;</p>
<p>
<xforms:select ref="/my/select">
  <xforms:label>select Form Control</xforms:label>
  <xforms:item>
    <xforms:label>1st</xforms:label>
    <xforms:value>1</xforms:value>
  </xforms:item>
  <xforms:item>
    <xforms:label>2nd</xforms:label>
    <xforms:value>2</xforms:value>
  </xforms:item>
  <xforms:item>
    <xforms:label>3rd</xforms:label>
    <xforms:value>3</xforms:value>
  </xforms:item>
</xforms:select>
</p>
    <p class="headline">&lt;button&gt;</p>
<xforms:trigger>
  <xforms:label>Click Me</xforms:label>
  <xforms:message level="ephemeral" ev:event="click" ref="/my/message"/>
</xforms:trigger>
    <p>
<xforms:selectboolean ref="/my/selectboolean">
  <xforms:label>Selectboolean</xforms:label>
</xforms:selectboolean>
</p>
    <p class="headline">&lt;selectBoolean&gt; (X-Smiles extension)</p>

<p>
<xforms:input ref="/my/selectboolean">
  <xforms:label>input</xforms:label>
</xforms:input>
</p>
    <p class="headline">&lt;submit&gt;</p>
<xforms:submit>
  <xforms:label>Submit Me</xforms:label>
</xforms:submit>
    <p class="headline">&lt;selectBoolean&gt; (X-Smiles extension)</p>
<p class="headline">&lt;reset&gt;</p>
<xforms:trigger>
  <xforms:label>Reset</xforms:label>
  <xforms:reset ev:event="DOMActivate"/>
</xforms:trigger>
</p>
</body>
</html>


More complex forms


Calculations

<instance>
  <my:order>
    <my:item>
      <my:amount />
      <my:discount />
    </my:item>
  </my:order>
</instance>
<bind nodeset="my:item/my:discount" 
      calculate="../my:amount * 0.1"
      type="xsd:decimal" />

SMS Message

<?xml version="1.0" encoding="ISO-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:xforms="http://www.w3.org/2002/xforms" 
      xmlns:ev="http://www.w3.org/2001/xml-events" 
      xmlns:my="test">
  <head>
    <link rel="stylesheet" type="text/css" href="xformsdemo.css" />
    <xforms:model id="form1">
      <xforms:submission id="submit1" method2="postxml" 
        localfile="temp2.xml" target2="http://www.hut.fi/"/>
      <xforms:instance id="instance1" xmlns="" >
        <sms>
          <number>555-556</number>
          <text/>
          <length>
            <current>0</current>
            <left></left>
            <maximum>160</maximum>
          </length>
        </sms>
      </xforms:instance>
      <xforms:bind ref="/sms/length/current" 
                   calculate="string-length(/sms/text)"/>
      <xforms:bind ref="/sms/length/left" 
                   calculate="../maximum - ../current" 
                   constraint="/sms/length/left &gt; -1"/>
    </xforms:model>
  </head>
<body>

<p class="headline">SMS Message</p>
<p>This example demonstrates the incremental changes to the instance.
Every character typed into the message will trigger the calculation of
the remaining characters.</p>
<p>
<xforms:input ref="/sms/number">
  <xforms:label>Telephone number</xforms:label>
</xforms:input>
</p>
<p>
<xforms:output ref="/sms/length/left" >
  <xforms:label>Characters left</xforms:label>
</xforms:output>
</p>
<p>
<xforms:textarea ref="/sms/text" incremental="true">
  <xforms:label>Message</xforms:label>
</xforms:textarea>
</p>
<p>
<xforms:trigger>
  <xforms:label>Duplicate</xforms:label>
  <xforms:setvalue ev:event="DOMActivate" ref="/sms/text" value="concat(.,.)"/>
</xforms:trigger>

</p>
<p>
<xforms:submit submission="submit1">
  <xforms:label>Send</xforms:label>
</xforms:submit>
</p>
</body>
</html>


Functions


Other features


Browser Implementations


Server side Implementations


Status

XForms is not a Web standard. It's a relatively new spec seeing early-adopter use in intranets.

--Brendan Eich

  1. Non-Web, non-browser environments that need forms such as OpenOffice 2.0

  2. Early adopter intranets that can install plug-ins

  3. Server-side conversion to legacy HTML+JavaScript

  4. Intranets that can standardize on Firefox

  5. Near universal adoption and availability


My Favorite XForms Features


My Least Favorite XForms Features


Coming Attractions: XForms 1.1


What about WHAT?


To Learn More


Index | Cafe con Leche

Copyright 2005 Elliotte Rusty Harold
elharo@metalab.unc.edu
Last Modified March 17, 2005