XForms

XForms in MathDox documents adds a means for communication with the reader of the MathDox document. It allows for many form elements which can be used for user-input, but it can also be used with a set of rules to bind entered data to specific conditions, or disable editing in some form elements or remove form elements all together from the web page, or the other way around. The next example shows how this works.

Example 1. 



<article xmlns:xforms='http://www.w3.org/2002/xforms'>
  <xforms:model>
    <xforms:instance>
      <model>
        <textarea>edit this text</textarea>
        <editable>off</editable>
        <visible>true</visible>
      </model>
    </xforms:instance>
    <xforms:bind
      nodeset='textarea'
      readonly='/model/editable="off"'/>
  </xforms:model>

  <xforms:group ref='visible[.="true"]'>
    <xforms:label>TextArea</xforms:label>
    <xforms:textarea ref='/model/textarea' />
  </xforms:group>

  <para>Turn editing :</para>
  <xforms:select1 ref='editable' appearance='full'>
    <xforms:item>
      <xforms:label>on</xforms:label>
      <xforms:value>on</xforms:value>
    </xforms:item>
    <xforms:item>
      <xforms:label>off</xforms:label>
      <xforms:value>off</xforms:value>
    </xforms:item>
  </xforms:select1>
<para/>
  <para>Turn visibility :</para>
  <xforms:select1 ref='visible'>
    <xforms:item>
      <xforms:label>visible</xforms:label>
      <xforms:value>true</xforms:value>
    </xforms:item>
    <xforms:item>
      <xforms:label>invisible</xforms:label>
      <xforms:value>false</xforms:value>
    </xforms:item>
  </xforms:select1>
</article>

This MathDox document shows three input elements in a web page. The first, a textarea, can be made readonly by the second control and made to disappear by the third. The example above is divided into four parts. The first is an internal model in which all variables and selections of the user are stored and which is send to the MathDox Player on a submit event. In this part there is also a bind rule, which can be used to impose restrictions on the XForms control and elements. This particularly bind element turns the readonly flag of the textarea (part two) on or off based on the model's editable element. The predefined values in the model are the default values. The other parts of the example contain the XForms controls. These are a textarea, radioboxes (select1) and a dropdown menu (again a select1). These controls are pointed to elements from the model and contain initially the same values as the elements of these forms.

See the example in action..


We describe a second example

Example 2. 


<article xmlns:xforms='http://www.w3.org/2002/xforms'>
  <xforms:model>
    <xforms:instance>
      <model><answer/></model>
    </xforms:instance>
  </xforms:model>
<para/>
  <para>
    What do you get if you multiply 
    <OMOBJ><OMI>6</OMI></OMOBJ> by <OMOBJ><OMI>9</OMI></OMOBJ> ?
  </para>
<para/>
  <orderedlist numeration="loweralpha">
    <listitem>
      <OMOBJ><OMI>42</OMI></OMOBJ>
    </listitem>
    <listitem>
      <OMOBJ><OMI>54</OMI></OMOBJ>
    </listitem>
  </orderedlist> 
<para/>
  <xforms:group ref='answer'>
    <xforms:label>Answer:</xforms:label>
    <xforms:select1 ref=".">
      <xforms:item>
        <xforms:label>no answer</xforms:label>
        <xforms:value>no answer</xforms:value>
      </xforms:item>
      <xforms:item>
        <xforms:label>a</xforms:label>
        <xforms:value>1</xforms:value>
      </xforms:item>
      <xforms:item>
        <xforms:label>b</xforms:label>
        <xforms:value>2</xforms:value>
      </xforms:item>
    </xforms:select1>
  </xforms:group>
<para/>
  <xforms:group ref="answer[ . = '1' ]">
    <para> This galaxy is not so twisted that 
      <OMOBJ>
        <OMA>
          <OMS cd="relation1" name="eq"/>
          <OMA>
            <OMS cd="arith1" name="times"/>
            <OMI>6</OMI>
            <OMI>9</OMI>
          </OMA>
          <OMI>42</OMI>
        </OMA>
      </OMOBJ>. Please try again.
    </para>
  </xforms:group>
  <xforms:group ref="answer[ . = '2' ]">
    <para>Your answer,
      <OMOBJ><OMI>54</OMI></OMOBJ>
      is correct!
    </para>
  </xforms:group>
</article>

This MathDox document is a multiple choice question. The reader is asked to answer a simple question by choosing the right answer between two options. Depending which answer was chosen by the reader a feedback is displayed, telling the reader if the answer was correct. This example is constructed out of 5 parts. At the top the document starts with a XForms model, which is used to store the answer of the reader of the MathDox document. Directly underneath the question is posed, followed by a list of possible answers to chose from. The fourth block gives the user a drop down menu which allows the reader to choose. The answer is stored in the model which was found in the first block. In the last block it is determined which feedback should be shown to the reader. The MathDox Player tries to find the reference to the answer element which contains a '1' (indicating that answer a was chosen) in the instance in the model, defined at the top of the document. If it is found then the xforms:group line becomes active and the included lines within this element are shown. Otherwise the answer must be '2' activating a different feedback in the same way.

View the example.


The next example shows how user input is taken care of by the use of XForms.

Example 3. 

In this example we show two user input fields for integers a and b. After the submit of the form, the integers are just displayed.


<article xmlns:x='jelly:xml'
         xmlns:xforms='http://www.w3.org/2002/xforms'>

  <title>Simple Form</title>

  <x:if select="not($formdata)">
    <!-- set default values -->
    <x:parse var="formdata">
      <variables>
        <a>1</a>
        <b/>
      </variables>
    </x:parse>
  </x:if>

  <!-- the XForms model -->
  <xforms:model>
    <xforms:instance>
      <x:copyOf select="$formdata/*"/>
    </xforms:instance>
  </xforms:model>

  <para>

    <!-- the XForms inputs -->
    <xforms:input ref='a'>
      <xforms:label>a</xforms:label>
    </xforms:input>
    <xforms:input ref='b'>
      <xforms:label>b</xforms:label>
    </xforms:input>

    <!-- the XForms submit button -->
    <xforms:submit submission='submission'>
      <xforms:label>submit</xforms:label>
    </xforms:submit>

  </para>

  <!-- some text containing the values  -->
  <para>
    a: <x:expr select='$formdata/*/a'/>
  </para>

  <para>
    b: <x:expr select='$formdata/*/b'/>
  </para>

</article>


We recognize various constructs within this code.

First, there is


  <x:if select="not($formdata)">
    <!-- set default values -->
    <x:parse var="formdata">
      <variables>
        <a>1</a>
        <b/>
      </variables>
    </x:parse>
  </x:if>


in which the Jelly XML variable formdata is created. In this variable we set the initial values of the various parameters.

Then there is


 <xforms:model>
    <xforms:instance>
      <x:copyOf select="$formdata/*"/>
    </xforms:instance>
  </xforms:model>

This is the model containing the actual information on the various parameters used in the form. It is filled with the information set in "formdata".

The input fields of the form are


<xforms:input ref='a'>
  <xforms:label>intger a</xforms:label>
</xforms:input>
<xforms:input ref='b'>
  <xforms:label>integer b</xforms:label>
</xforms:input>

Finally, the values of the elements a and b are obtained by using


<x:expr select='$formdata/*/a'/>

and


<x:expr select='$formdata/*/b'/>

See the example working.


Example 4. 

In this final example we show two user input fields for integers a and b. After the submit of the form, the integers are added. This is done using a Monet query.


<article xmlns:c='jelly:core'
         xmlns:monet='http://monet.nag.co.uk/monet/ns'
         xmlns:om='http://www.openmath.org/OpenMath'
         xmlns:x='jelly:xml'
         xmlns:xforms='http://www.w3.org/2002/xforms'>

  

<title>XForms Example</title>
 
  <x:parse var='default_aa'>
    <om:OMOBJ>
      <om:OMI>1</om:OMI>
    </om:OMOBJ>
  </x:parse>

  <c:set var='default_a' trim='true'>
    <om:OMOBJ>
      <om:OMI>1</om:OMI>
    </om:OMOBJ>
  </c:set>

  <c:set var='default_b' trim='true'>
    <om:OMOBJ>
      <om:OMI>2</om:OMI>
    </om:OMOBJ>
  </c:set>

  <x:if select='not(formdata)'>  
    <x:parse var='formdata'>
      <variables>
        <a>
          <c:out value=''/>
        </a>
        <b>
          <c:out value=''/>
        </b>
      </variables>
    </x:parse>
  </x:if>

  <!-- 
    Copy the formdata (default or submitted)
  -->
  <xforms:model>
    <xforms:instance>
      <x:copyOf select='formdata/*'/>
    </xforms:instance>
  </xforms:model>

  <para>

    <xforms:textarea ref='a' class='math-editor'>
      <xforms:label>integer a:</xforms:label>
    </xforms:textarea>
    <xforms:textarea ref='b' class='math-editor'>
      <xforms:label>integer b:</xforms:label>
    </xforms:textarea>

    <xforms:submit submission='submission'>
      <xforms:label>submit</xforms:label>
    </xforms:submit>

  </para>

  <!-- 
    convert the form variables to xml
    note, this will give an error if the input is not xml
    exceptions can be caught with c:catch
  -->
  <c:set var='a_text' encode='false'>
    <x:expr select='formdata/*/a'/>
  </c:set>
  <x:parse var='a_xml' text=''/>

  <c:set var='b_text' encode='false'>
    <x:expr select='formdata/*/b'/>
  </c:set>
  <x:parse var='b_xml' text=''/>

  <!-- calculate a+b and place the result in aplusb -->
  <x:parse var='aplusb'>
    <monet:query>
      <monet:classification>
        <monet:directive-type href='http://mathdox.org/phrasebook/default#eval'/>
      </monet:classification>
      <monet:body>
        <monet:output>
          <om:OMOBJ>
            <om:OMA>
              <om:OMS cd='arith1' name='plus'/>
              <x:copyOf select='a_xml/om:OMOBJ/*'/>
              <x:copyOf select='b_xml/om:OMOBJ/*'/>
            </om:OMA>
          </om:OMOBJ>
        </monet:output>
      </monet:body>
    </monet:query>
  </x:parse>

  <para>
    <om:OMOBJ>
      <om:OMV name='a'/>
    </om:OMOBJ>
    : <x:copyOf select='a_xml/*'/>
  </para>

  <para>
    <om:OMOBJ>
      <om:OMV name='b'/>
    </om:OMOBJ>
    : <x:copyOf select='b_xml/*'/>
  </para>

  <para>
    <om:OMOBJ>
      <om:OMA>
        <om:OMS cd='arith1' name='plus'/>
        <om:OMV name='a'/>
        <om:OMV name='b'/>
      </om:OMA>
    </om:OMOBJ>
    :
    <om:OMOBJ>
      <om:OMA>
        <om:OMS cd='relation1' name='eq'/>
        <om:OMA>
          <om:OMS cd='arith1' name='plus'/>
          <x:copyOf select='a_xml/om:OMOBJ/*'/>
          <x:copyOf select='b_xml/om:OMOBJ/*'/>
        </om:OMA>
        <x:copyOf select='aplusb/*/*'/>
      </om:OMA>
    </om:OMOBJ>
  </para>
  
</article>

This example has roughly the same structure as the above. However, in the handling of the variables we some difference.

The intial values of the variables are stored as strings in the Jelly c-variable default_a and default_b . These strings are then written inside the XML variable formaldata .

To use these variables as XML again, one writes their value in a string-variable like


<c:set var='a_text' encode='false'>
  <x:expr select='$formdata/*/a'/>
</c:set>
 

and then parses them to XML by


<x:parse var='a_xml' text=''/>
 

Now the variables are ready to be used inside the Monet query:


<monet:query>
  <monet:classification>
    <monet:directive-type href='http://mathdox.org/phrasebook/default#eval'/>
  </monet:classification>
  <monet:body>
    <monet:output>
      <om:OMOBJ>
        <om:OMA>
          <om:OMS cd='arith1' name='plus'/>
          <x:copyOf select='a_xml/om:OMOBJ/*'/>
          <x:copyOf select='b_xml/om:OMOBJ/*'/>
        </om:OMA>
      </om:OMOBJ>
    </monet:output>
  </monet:body>
</monet:query>

See the example working (only if the maxima service is set up properly).