XQuery/Simple XForms Examples

From Wikibooks, open books for an open world
Jump to: navigation, search

Motivation[edit]

Although static XForms can be held in the eXist database, XForms can also be generated dynamically using XQuery. In this section, we first show static forms being output and executed by some XForms client-side engines, the FireFox add-in, the Javascript FormFaces and the XSLT/Javascript XSLTForms.

Then we look at dynamic form generation.

A wide range of XForms examples can be found in the XForms Wikibook

XForms Engines[edit]

These examples use:

  • Firefox addin
    • Requires Firefox with the XForms add-in
    • media-type set to application/xhtml+xml
  • FormFaces
    • Cross-browser support - examples tested on Firefox and IE6
    • The Javascript source is stored in the eXist database and linked to each form
    • media-type set to text/html
  • XSLTForms
    • Uses XSLT to transform to an HTML page and JavaScript to execute.
    • The XSLT transformation may be either server-side (via eXist) or client-side.

All examples use the same css stylesheet

XForm Output[edit]

Firefox[edit]

declare option exist:serialize "method=xhtml media-type=application/xhtml+xml indent=yes";
 
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:form="http://www.w3.org/2002/xforms" xml:lang="en">
   <head>
      <title>Output a Model value</title>
         <form:model>
            <form:instance>
                <data xmlns="">
                    <name>Mozilla XForms add-in</name>
               </data>
            </form:instance>
        </form:model>
   </head> 
   <body>
       <h2>
             <form:output ref="name"></form:output>
       </h2>
   </body>
</html>

Execute

FormFaces[edit]

declare option exist:serialize "method=xhtml media-type=text/html indent=yes";

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:form="http://www.w3.org/2002/xforms" xml:lang="en">
   <head>
      <title>Output a Model value</title>
         <script language="javascript" src="../formfaces/formfaces.js"/>
         <link rel="stylesheet" type="text/css" href="xforms.css" />
         <form:model>
            <form:instance>
                <data xmlns="">
                    <name>Formfaces</name>
               </data>
            </form:instance>
        </form:model>
   </head> 
   <body>
       <h2>
             <form:output ref="name"></form:output>
       </h2>
   </body>
</html>

Execute

XSLTForms[edit]

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="ajaxforms.xsl" type="text/xsl"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:form="http://www.w3.org/2002/xforms" xml:lang="en">
   <head>
      <title>Output a Model value</title>
         <script language="javascript" src="formfaces.js"/>
         <link rel="stylesheet" type="text/css" href="xforms.css" />
         <form:model>
            <form:instance>
                <data xmlns="">
                    <name>Formfaces</name>
               </data>
            </form:instance>
        </form:model>
   </head> 
   <body>
       <h2>
             <form:output ref="name"></form:output>
       </h2>
   </body>
</html>

Execute

Simple Controls[edit]

Firefox Formfaces XSLTForms

Observations[edit]

  • FormFaces : breaks on Firefox
  • XSLTForms : Changes only made when triggered

Multiple instances[edit]

A model can contain multiple instances, whose root node is accessed with the instance(id) construct.

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:xf="http://www.w3.org/2002/xforms"   
      xmlns:ev="http://www.w3.org/2001/xml-events">
   <head>
      <title>Test conditional selection lists</title>
      <xf:model>
         <xf:instance id="data" xmlns="">
            <data>
               <selected-season>spring</selected-season>
               <selected-month>March</selected-month>
            </data>
         </xf:instance>
         <xf:instance id="seasons" xmlns="">
            <seasons>
               <item name="winter"/>
               <item name="spring"/>
               <item name="summer"/>
               <item name="autumn"/>    
            </seasons>
         </xf:instance>
         <xf:instance id="months" xmlns="">
            <months>
               <item name="January" season="winter"/>
               <item name="February" season="winter"/>
               <item name="March" season="spring"/>
               <item name="April" season="spring"/>
               <item name="May" season="spring"/>
               <item name="June" season="summer"/>
               <item name="July" season="summer"/>
               <item name="August" season="summer"/>
               <item name="September" season="autumn"/>
               <item name="October" season="autumn"/>
               <item name="November" season="autumn"/>
               <item name="December" season="winter"/>
            </months>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <p>Test conditional selection lists - 
         month selector depends on the current season</p>   
      <div>
         <xf:select1 ref="instance('data')/selected-season">
           <xf:label>Season:</xf:label>
           <xf:itemset nodeset="instance('seasons')/item">
             <xf:label ref="@name"/>
             <xf:value ref="@name"/>
           </xf:itemset>            
         </xf:select1>
      </div>
      <div>
         <xf:select1 ref="instance('data')/selected-month">
           <xf:label>Month:</xf:label>
           <xf:itemset nodeset="instance('months')/item[@season=instance('data')/selected-season]">
             <xf:label ref="@name"/>
             <xf:value ref="@name"/>
           </xf:itemset>            
         </xf:select1>
      </div>
      <div>
         <xf:output ref="instance('data')/selected-season">
            <xf:label>selected-season: </xf:label>
         </xf:output>
         <xf:output ref="instance('data')/selected-month">
            <xf:label>selected-month: </xf:label>
         </xf:output>
      </div>
   </body>
</html>

FireFox

Date Entry[edit]

  • Firefox generates a drop-down calendar. Firefox
  • Formfaces currently has no Calendar widget Formfaces

Server Interaction[edit]

Interaction with a server can be via GET or POST. This example is based on Dan McCreary's example in the XForms Wiki book.

On Firefox:

<html xmlns:xf="http://www.w3.org/2002/xforms" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>XQuery Tester</title>
         <link rel="stylesheet" type="text/css" href="xforms.css" />
    
        <xf:model>
            <xf:instance>
                <data xmlns="">
                  <input>
                    <arg1>123</arg1>
                    <arg2>456</arg2>
                </input>
                <result>
                    <sum>0</sum>
                 </result>
                 </data>
            </xf:instance>
            
            <xf:submission id="get-instance"  method="get" replace="instance" 
                action="adderGet.xq"
                separator="&">
            </xf:submission>          
            
            <xf:submission id="post-instance" method="post"  replace="instance"
                 action="adderPost.xq">
            </xf:submission>
            
         </xf:model>
    </head>
    <body>
        <h1>XForm interaction with XQuery</h1>
        <xf:input ref="input/arg1" incremental="true">
            <xf:label>Arg1:</xf:label>
        </xf:input>
        <br/>
        <xf:input ref="input/arg2" incremental="true">
            <xf:label>Arg2:</xf:label>
        </xf:input>
        <br/>
        <xf:output ref="result/sum">
            <xf:label> Sum:</xf:label>
        </xf:output>
        <br/>
        
        <xf:submit submission="get-instance">
            <xf:label>Get</xf:label>
        </xf:submit>
        
        <xf:submit submission="post-instance">
            <xf:label>Post</xf:label>
        </xf:submit>
        <p id="status"></p>
    </body>
</html>

Firefox Formfaces


The respective server scripts are

  • GET
xquery version "1.0";
declare namespace request="http://exist-db.org/xquery/request";

let $arg1 := number(request:get-parameter("arg1", "0"))
let $arg2 := number(request:get-parameter("arg2", "0"))
return
<data xmlns="">
  <input>
    <arg1>{$arg1}</arg1>
    <arg2>{$arg2}</arg2>
  </input>
  <result>
     <sum>{$arg1+$arg2}</sum>
   </result>
</data>

  • POST
xquery version "1.0";
declare namespace request="http://exist-db.org/xquery/request";

let $data := request:get-data()

let $arg1 := number($data/arg1)
let $arg2 := number($data/arg2)
return
<data xmlns="">
  <input>
    <arg1>{$arg1}</arg1>
    <arg2>{$arg2}</arg2>
  </input>
  <result>
     <sum>{$arg1+$arg2}</sum>
   </result>
</data>

In this example, the whole model is updated and returned to the client. Alternatively, part of the model can be updated (tbc)


Generic XForms[edit]

Tabular example[edit]

A simple approach to generic XForms is illustrated in this script based on an example in the XForms wikibook

declare option exist:serialize "method=xhtml media-type=application/xhtml+xml indent=yes";

let $data :=           
<Data>
               <GivenName>John</GivenName>
               <MiddleName>George</MiddleName>
               <Surname>Doe</Surname>
               <CityName>Anytown</CityName>
               <StateCode>MM</StateCode>
               <PostalID>55123-1234</PostalID>
</Data>
return

<html xmlns:xf="http://www.w3.org/2002/xforms" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Formatting XForms</title>
        <link rel="stylesheet" type="text/css" href="xforms.css" />

        <style type="text/css">
{
  for $item in $data/*
  let $width := string-length($item) 
  return concat('._',name($item),' .xf-value {width:', $width,'em}
')
}
   </style>
      <xf:model>
         <xf:instance xmlns="">
           {$data}
          </xf:instance>
      </xf:model>
   </head>
   <body>
      <fieldset>
      <legend>Name and Address</legend>
      {for $item in $data/*
       return 
        (
       <xf:input class="_{name($item)}" ref="/Data/{name($item)}">
         <xf:label>{name($item)}:  </xf:label>
       </xf:input>,
        <br/>
        )
     }
       </fieldset>
     </body>
</html>

In this simple tabular example, the XForm and accompanying CSS to define input field widths is generated by reflection on the supplied instance.

This example works correctly in Firefox but the styling fails in Formfaces


Simple Forms Schema[edit]

More control over the generated XForms can be provided by a simple Schema. This example is still for a simple tabular structure:

declare option exist:serialize "method=xhtml media-type=application/xhtml+xml indent=yes";

let $data :=           
<Data>
               <GivenName>John</GivenName>
               <MiddleName>George</MiddleName>
               <Surname>Doe</Surname>
               <CityName>Anytown</CityName>
               <StateCode>MM</StateCode>
               <PostalID>55123-1234</PostalID>
 </Data>
 
 let $schema := 
 <Schema>
     <Row name="GivenName" label="First Name" width="20"/>
     <Row name="Surname" label="Surname" width="15"/>
     <Row name="CityName" label="City" width="15"/>
     <Row name="StateCode" label="State" width="3"/>
    <Row name="PostalID" label="ZipCode" width="8"/>
 </Schema>
return

<html xmlns:xf="http://www.w3.org/2002/xforms" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Formatting XForms</title>
        <link rel="stylesheet" type="text/css" href="xforms.css" />

        <style type="text/css">
{
  for $item in $schema/*
  let $id := concat("_",$item/@name)
  let $width := $item/@width 
  return concat('.',$id,' .xf-value {width:', $width,'em}
')
}
   </style>
      <xf:model>
         <xf:instance xmlns="">
           {$data}
          </xf:instance>
      </xf:model>
   </head>
   <body>
      <fieldset>
      <legend>Name and Address</legend>
      {for $item in $schema/*
        let $id := concat("_",$item/@name)
        let $label := string( $item/@label)
       return 
        (
       <xf:input class="{$id}" ref="/Data/{$item/@name}">
         <xf:label>{$label}:  </xf:label>
       </xf:input>,
        <br/>
        )
     }
       </fieldset>
     </body>
</html>

Firefox