XForms Designer
Contents |
Abstract
OpenMRS supports the XForms standard for the development and implementation of structured medical record forms. Currently, OpenMRS is tightly bound to implementation in Microsoft InfoPath which also requires Microsoft InfoPath (or a commercial application) to complete and submit the forms. A project is already underway to extend the functionality of OpenMRS to include full support for XForms including browser-based form-filling. The aim of this project is to develop options for designing XForms developed using an open source schema design application, such as OpenMRS. This project will cooperate closely with the XForms in OpenMRS projects.
This project stems out of the OpenMRS internship program OIP and focuses on providing an alternative form designer for XForms to the current Microsoft InfoPath application.
Project Plan
The Designer will be leveraging off the ideas presented by the excel reporting template to allow for a syllable XForm to be generated from within OpenMRS. A very simple walk through would be as follows:
An implementer would log onto OpenMRS and begin to design a form using the current form schema designer found within OpenMRS. Once the schema is designed (the schema will form the Xform model) the user will select “Style XForm”. This will download an un-styled html/xhtml template to the user’s system. The user will be able to open the template within any WYSIWYG HTML designer and apply the necessary styling to the template. The template will contain place-holders / tags which will be replaced, upon upload back to OpenMRS, with the relevant Xforms controls.
The initial template will follow a similar idea to the current InfoPath template as in providing an editable default layout for the initial patient information but where as InfoPath provides the schema listed in an additional window the designer will list these out upon the form.
Xforms styling and layout template:
<html>
...
<table>
<tr>
<td>#@_WEIGHT (KG).conceptName.1234_@#</td> <!-- in this case 1234 means formFieldId=1234 -->
<td>#@_WEIGHT (KG).value.1234_@#</td>
<td>#@_WEIGHT (KG).obsDatetime.1234_@#</td>
<td><span class="errorMessage">#@_WEIGHT (KG).errorMessage.1234_@#</span></td>
</tr>
</table>
...
</html>
When someone goes to fill out the form, the xforms modules will take this uploaded html, insert the xforms model into the HEAD, and replace all the @...@ stuff with <xf:input/>, etc. The tags will be dynamically assigned input controls dependent on the meta-data existing around the fields and the data it collects. At this stage this information will be drawn out of the concept dictionary until the form section of the data model is elaborated to provide a very rich meta-data environment around the form (if actually needed).
Design
The initial design of the XForms designer is outlined below. A simple step through: a request for an XForm is issued (i.e. the user is requesting to complete a form within OpenMRS), this request is passed on to the main Template Manager. The request includes the id of the form the user wishes to recieve. This id is passed along with the Template ID (an assumption is made that the template id is passed to the main Template manager with the request for the XForm) to the Generator. The Generator issues requests to the XForms Factory for the corrosponding XForm, the Template Factory for the relative template (XHTML style mask) and the Mapping Factory for the mapping of controls to stubs within the template. These are then processed and parsed to generate a dynamically styled XForm ready for completion.
The various Factories which exist are in place to allow for a more configurable contribution and facilitate change on a rapid level. Each Factory, at this point, consists of a manager, a retrieval engine and options templates. These allow the easy creation of a straight through floss approach by letting us bound our assumptions on the origines of the various components provided by the factory and change these at a later point with very litte alteration to the rest of the application.
The XForms Factory at this point allows us to abstract out the complexity of obtaining the XForm in a correct format. It allows us to assume that the forms are available and easily accessable. The first pass at this we will creat a retrieval option that simply allows me to provide a predefined XForm from the file system to prove the concept of the designer. At a later stage this retrieval process will be elaborated to allow for retrieval from the core (more likely the xformsorbeon module at this point in time).
The Template Factory again follows the same principles of the XForms Factory in abstracting away the complexities of storing the templates and retrieving them initially. Again this will be a first pass consisting of a set template supplied by one of the Template Options Templates with this evloving as the design pushes more towards a working (off the database) module.
The Mapping Factory is where the Mapping Templates options come into their own. For a start the mapping will be hard coded as an XForm_Control_1-->Template:stub_XYZ but by having thie Mapping Generation Engine work off options one allows for the future generation of the mappings dynamically from the data model of the XForm or even OpenMRS in the future.
Tasks
- The first task is to provide a very simple straight through approach to this design. This will involve the creation of a template engine with will read in a mapping template which will contain a mapping of xform controls to stubs/tags and allow this to be run against a styled layout file (xhtml /html file). This will do a find and replace for the various controls.
- The second task will be to evolve the template engine away from fully defined xform controls in the mapping file but rather to form fields and translate these into input controls on the form.
- The third task (which should be viewed more along the lines of task 2.5) is to build in an intelligence engine which will, based upon a set of rules, define which input controls to dynamically assign to the various input fields.
- The fourth task involves the configuring of these rules into a “language” which would allow different implementations to assign different rules on how they expect their fields to be interpreted.
Future features may include:
- The extension of the form schema designer to allow the user to define the style of input required as they are defining the form.
Progress
Below I have inserted the contents of the 3 components of the designer and parser engine (Mapping.xml, Template.xhtml and XForm_src.xml) these file form the basic building blocks and will be used to style the XForm.
The XForm_src.xml represents the output of the Xforms Factory given the xform_id.
The Mapping.xml shows the response of the Mapping Factory to the request for the mapping of the given template_id to the supplied xform_id.
The Template.xhtml is the template file designed by any HTML designer (i.e Dreamweaver etc) with the tags in place prefixed with #@_ and postfixed with _@# (i.e. #@_xxx_@#)
As for the rendering of the XForm, Firefox 3 seems to be having trouble with the Mozilla XForm component but I have begun looking at FormFaces which provides a JavaScript engine to interpret XForm markup and display it in html with the required interactions. An example of this is seen at example
Template.xhtml
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <head> <title>Your Title Here</title> #@_MODEL_@# </head> <body> <table border="1"> <tr> <td>#@_FIRSTNAME_@#</td> </tr> <tr> <td>#@_LASTNAME_@#</td> </tr> <tr> <td>#@_OUTPUT_FIRSTNAME_@#</td> </tr> <tr> <td>#@_OUTPUT_LASTNAME_@#</td> </tr> </table> </body> </html>
Mapping.xml
<root> <mapping> <stub>#@_MODEL_@#</stub> <control> <xf:model> <xf:instance xmlns=""> <data> <PersonGivenName/> <PersonSurName/> </data> </xf:instance> <xf:bind id="PersonGivenName" nodeset="/data/PersonGivenName"/> <xf:bind id="PersonSurName" nodeset="/data/PersonSurName"/> </xf:model> </control> </mapping> <mapping> <stub>#@_FIRSTNAME_@#</stub> <control> <xf:input bind="PersonGivenName" incremental="true"> <xf:label>Input First Name:</xf:label> </xf:input> </control> </mapping> <mapping> <stub>#@_LASTNAME_@#</stub> <control> <xf:input bind="PersonSurName" incremental="true"> <xf:label>Input Last Name:</xf:label> </xf:input> </control> </mapping> <mapping> <stub>#@_OUTPUT_FIRSTNAME_@#</stub> <control> <xf:output bind="PersonGivenName"> <xf:label>Output First Name:</xf:label> </xf:output> </control> </mapping> <mapping> <stub>#@_OUTPUT_LASTNAME_@#</stub> <control> <xf:output bind="PersonSurName"> <xf:label>Output Last Name:</xf:label> </xf:output> </control> </mapping> </root>
XForm_src.xml
<xform> <xf:model> <xf:instance xmlns=""> <data> <PersonGivenName/> <PersonSurName/> </data> </xf:instance> <xf:bind id="PersonGivenName" nodeset="/data/PersonGivenName"/> <xf:bind id="PersonSurName" nodeset="/data/PersonSurName"/> </xf:model> <controls> <xf:input bind="PersonGivenName" incremental="true"> <xf:label>Input First Name:</xf:label> </xf:input> <xf:input bind="PersonSurName" incremental="true"> <xf:label>Input Last Name:</xf:label> </xf:input> <xf:output bind="PersonGivenName"> <xf:label>Output First Name:</xf:label> </xf:output> <xf:output bind="PersonSurName"> <xf:label>Output Last Name:</xf:label> </xf:output> </controls> </xform>

