XForms/Selecting Codes From File

From Wikibooks, the open-content textbooks collection

< XForms
Jump to: navigation, search
Best Practice

Contents

[edit] Motivation

People that design forms frequently have to maintain many code tables. These code tables may change frequently and there may be processes that update a database of centrally maintained code tables. So you want each form to dynamically get the current relevant codes from and XML file or a RESTful web service.

This sample program demonstrates how to read a list of codes with labels directly from a file or code-table web service. In this example the file that contains the codes is just a well-formed XML file in the same directory that the form is located in.

[edit] Loading XML instance data from a local file or web service

The following code fragment, usually in the HTML head, demonstrates how to read XML data from a local file in the same directory as the form by using the "src" attribute of the instance.

[edit] Loading a Single Codes Table into a Single Instance

<html>
   <xf:model>
      <xf:instance src="XMLSchemaTypeCode.xml" id="XMLSchemaTypeCode"/>
   </xf:model>
</html>

[edit] Loading all Codes into a single Instance

<html>
   <xf:model>
      <xf:instance src="/db/mdr/services/all-codes.xq?form=DataElementManager&group=admin"/>
   </xf:model>
</html>

In this second example all the codes in the entire form are generated by a service of the Metadata Registry (MDR). The data returned by this server is a collection of codes for each select1 control in the form.

This will look for a well-formed XML file in the current directory and load it into the model instance.

Note that in this case the model is given an id. This is necessary to allow multiple code tables to each be read into their own separate model.

[edit] Screen Image

Here is a screen image of the program. As the user selects from the drop-down list, the value of the output is immediately updated.

XForms-select-from-file.jpg

Note that label on the screen is not the same as the label stored in the model.

[edit] Sample Program

<html
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:xf="http://www.w3.org/2002/xforms" >
   <head>
      <title>Select List From File</title>
 
      /* the default model */
      <xf:model>
         <xf:instance xmlns="">
            <MyData>
                  <MyXMLSchemaTypeCode/>
            </MyData>
         </xf:instance>
      </xf:model>
 
      /* read the codes from an external file into this model */
      <xf:model id="XMLSchemaTypeCode">
         <xf:instance src="XMLSchemaTypeCode.xml"/>
      </xf:model>
 
   </head>
   <body>
      <p>This selection list was read from a file.</p>
      <xf:select1  ref="/MyData/MyXMLSchemaTypeCode">
         <xf:label>Select XML Schema data type: </xf:label>
         <xf:itemset model="XMLSchemaTypeCode" nodeset="/XMLSchemaTypeCode/item">
            <xf:label ref="label"/>
            <xf:value ref="value"/>
         </xf:itemset>
      </xf:select1>
      <br/>
      <xf:output ref="/MyData/MyXMLSchemaTypeCode">
         <xf:label>Value of MyXMLSchemaTypeCode: </xf:label>
      </xf:output>
   </body>
</html>

[edit] Sample XML Data

<?xml version="1.0" encoding="UTF-8"?>
<XMLSchemaTypeCode>
   <label>XML Schema Type:</label>
   <item>
      <label>Date and Time</label>
      <value>dateTime</value>
   </item>
   <item>
      <label>Time (HH:MM:SS-06:00)</label>
      <value>time</value>
   </item>
   <item>
      <label>Date (yyyy-mm-dd)</label>
      <value>date</value>
   </item>
   <item>
      <label>Year and Month</label>
      <value>gYearMonth</value>
   </item>
   <item>
      <label>Year (nnnn)</label>
      <value>gYear</value>
   </item>
   <item>
      <label>Month and Day</label>
      <value>gMonthDay</value>
   </item>
   <item>
      <label>Day of Month (1 .. 31)</label>
      <value>gDay</value>
   </item>
   <item>
      <label>Month (1 .. 12)</label>
      <value>gMonth</value>
   </item>
   <item>
      <label>String</label>
      <value>string</value>
   </item>
   <item>
      <label>Boolean (true/false)</label>
      <value>boolean</value>
   </item>
   <item>
      <label>Base 64 Binary</label>
      <value>base64Binary</value>
   </item>
   <item>
      <label>Decimal (0.00)</label>
      <value>decimal</value>
   </item>
   <item>
      <label>Any URI</label>
      <value>anyURI</value>
   </item>
   <item>
      <label>Integer (...,-2,-1,0,1,2,...)</label>
      <value>integer</value>
   </item>
   <item>
      <label>Non-Positive Integer (...,-2,-1,0)</label>
      <value>nonPositiveInteger</value>
   </item>
   <item>
      <label>Negative Integer (...,-2,-1)</label>
      <value>negativeInteger</value>
   </item>
   <item>
      <label>Long (-9,223,372T .. 9,223,372T)</label>
      <value>long</value>
   </item>
   <item>
      <label>Int (-2,147,483,648 .. 2,147,483,647)</label>
      <value>int</value>
   </item>
   <item>
      <label>Short (-32,768 .. 32,767)</label>
      <value>short</value>
   </item>
   <item>
      <label>Byte (-128 .. 127)</label>
      <value>byte</value>
   </item>
   <item>
      <label>Non-negative Integer (0..N)</label>
      <value>nonNegativeInteger</value>
   </item>
    <item>
      <label>Positive Integer (1..N)</label>
      <value>positiveInteger</value>
   </item>
   <item>
      <label>Unsigned Long (0 .. 18,446,744T)</label>
      <value>unsignedLong</value>
   </item>
   <item>
      <label>Unsigned Int (0 .. 4,294,967,295)</label>
      <value>unsignedInt</value>
   </item>
   <item>
      <label>Unsigned Short (0.. 65,535)</label>
      <value>unsignedShort</value>
   </item>
   <item>
      <label>Unsigned Byte (0..255)</label>
      <value>unsignedByte</value>
   </item>
</XMLSchemaTypeCode>

Note that to be well-formed the XML file MUST contain a root data element that must match the node-set argument.

[edit] Extracting data from an XML REST web service

You can replace the instance src attribute with a path directly to a XML REST web service. For example, if you put all your code tables into a project resources collection the path would look like the following:

<xf:instance src="../resources/code-tables/PersonGenderCode.xml"/>

or if your system codes are stored in a single XML file and you have a wrapper XQuery

<xf:instance src="../resources/code-tables/get-codes-for.xq?element=PersonGenderCode"/>

[edit] Selection Lists From A Single Instance

To keep your forms fast, it is usually better to do a single HTTP GET operation for all your codes. Forms that have many selection lists will take a long time to load if each list does a seperate HTTP GET operation. For large forms it is easy to get a 10x speedup in form load times.

[edit] Structure of Code Tables Instance

The following is a sample structure of all codes loaded into a single instance:

<xf:instance id="code-tables">
   <code-tables>
      <code-table>
         <code-table-name>MyElementCode</code-table-name>
         <items>
            <item>
               <label>Joe Smith</label>
               <value>42</label>
            </item>
            <item>
               <label>Sue Johnson</label>
               <value>47</label>
            </item>
         <items>
      </code-table>
      <code-table>
         <code-table-name>ColorCode</code-table-name>
         <items>
            <item>
               <label>Red</label>
               <value>1</label>
            </item>
            <item>
               <label>Orange</label>
               <value>2</label>
            </item>
         <items>
      </code-table>
   </code-tables>
</xf:instance>

[edit] Sample Select1

Once your data is loaded into your model, each of your select1 or select controls can get its data directly from the mode using the xf:itemset element. Itemset works just like repeat and uses nodeset (not ref) to get all its values.

<xf:select1 ref="instance('save-data')/MyElementName">
   <xf:label>My Element:</xf:label>
   <xf:itemset nodeset="instance('code-tables')/code-table[code-table-name='MyElementCode']/items/item">
       <xf:label ref="label"/>
       <xf:value ref="value"/>
   </xf:itemset>
</xf:select1>

[edit] Discussion

When a group of complex forms that share common codes need to be placed in their own directory and yet still link to a central directory of codes, you can also use relative code table linking. For example a sibling directory could be called "code-tables" and the src="MyCode.xml" statement could be modified to be src="../code-tables/MyCode.xml".

If you have an XML Schema for the form you can also extract a list of all enumerations for each simpleType. This list of codes can then be passed to a web service that creates a list of all the codes in your registry. This allows the form to automatically be updated when new codes are added to the XML Schema.

If you have a RESTful web service that contains all the codes for a form, you can replace this web service URI for the XML file.

[edit] References

Next Page: Selecting a Date | Previous Page: Selecting from Model

Home: XForms