Creating Applications: Adding Multivalued Fields

Although some applications only require multiple-choice fields where only a single value may be chosen, in many situations it is desirable to be able to choose an arbitrary number of values for a particular field. However, up to this point, we have been content to represent form data using a single attribute on a single element to represent any given field value. With multivalued fields, we must choose a different strategy in using XML to represent such information.

Let us consider permitting multiple type values to be associated with our items. We revise our form data structure to be the following:

<?xml version="1.0"?>
<structure>
<item value="some value">
<types>
<type value="some type"/>
<type value="some other type"/>
</types>
<subitem subvalue="some other value"/>
</item>
</structure>

Multivalued Fields

We shall now take advantage of those HTML form fields which permit users to select one or many values presented in a list or menu.

Some item: 

Item type:

Itself containing more items:

Sub-item:

From the item type list many value may now be selected.

Taking the example HTML code from before, we can add a definition of this new list to the template to produce something like this:

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:template="http://www.boddie.org.uk/ns/xmltools/template">
<head>
<title>Example</title>
</head>
<body template:element="structure">
<form action="" method="POST">

<!-- Template text between the start and the interesting part. -->

<div template:element="item">
<p>
Some item: <input template:attribute="value" name="{template:this-attribute()}" type="text" value="{$this-value}" />
<input name="remove={template:this-element()}" type="submit" value="Remove" />
</p>
<p template:element="types">
Item type:
<select template:element="type" name="{template:list-attribute('value')}" multiple="multiple">
<option template:element="type-enum" template:expr="@value-is-set" template:expr-attr="selected"
template:value="@value" value="{@value}" />
</select>
</p>
<p>
Itself containing more items:
</p>
<p template:element="subitem">
Sub-item: <input template:attribute="subvalue" name="{template:this-attribute()}" type="text" value="{$this-value}" />
<input name="remove2={template:this-element()}" type="submit" value="Remove" />
</p>
<p>
<input name="add2={template:this-element()}" type="submit" value="Add subitem" />
</p>
</div>
<p>
<input name="add={template:this-element()}" type="submit" value="Add item" />
</p>

<!-- Template text between the interesting part and the end. -->

</form>
</body>
</html>

From the previous single-valued case, some crucial changes have been made:

  1. The paragraph surrounding the field has been annotated to map onto the types element in the form data structure.
  2. The select element remains mapped onto the type element in the form data structure. However, we indicate in the name of the select element that the value submitted maps onto a special kind of attribute. Instead of mapping onto a single attribute on a single element, the value maps onto a single attribute on a single element for each value submitted. So for each value selected in the list or menu, a type element is created with the value attribute containing that value.
  3. Of course, the select element now has a multiple attribute defined to permit multiple value selections.
  4. Inside the select element, the option element mapping onto a type-enum element using a different template:expr condition than was used before.

Output Structures

Just as in the single-valued case, the revised the form data structure for input does not quite match the structure used by the template. Therefore, we shall define an output form data structure as follows:

<?xml version="1.0"?>
<structure>
<item value="some value">
<types>
<type>
<type-enum value="some type"/>
<type-enum value="some other type"/>
</type>
</types>
<subitem subvalue="some other value"/>
</item>
</structure>

It is worth noting that the above structure does not define whether many type elements will exist within each types element or whether another mechanism will be used to specify multiple values for each type field.

Presenting the Extra Values

In most respects, the presentation of the extra values is the same as in the single-valued case. The result of the presentation of the extra values is that the types element in the this example structure fragment...

<types>
<type>
<type-enum value="1"/>
<type-enum value="2" value-is-set="true"/>
<type-enum value="3" value-is-set="true"/>
</type>
</types>

...is transformed into something resembling this HTML code:

<p>
<select name="..." multiple="multiple">
<option value="1">1</option>
<option value="2" selected="selected">2</option>
<option value="3" selected="selected">3</option>
</select>
</p>

Numerous issues arise when considering the above transformation:

Here, we have made a strategic decision: with the template as defined above, many type elements would have produced many select elements in the Web form, yet this is not what we want; we need to restrict the number of select elements to one per types element whilst marking the selected values so that they may be displayed appropriately in the list or menu.

Merging and Collecting Values

As in the single-valued case, we need to insert the permitted values into the form data so that the template may visit the type-enum elements and extract those values. However, we have now introduced another task to this activity: to collect the selected values together and to produce a unified type element within each types element. In other words, we want to turn something like this...

<types>
<type value="2"/>
<type value="3"/>
</types>

...into something like this:

<types>
<type>
<type-enum value="1"/>
<type-enum value="2" value-is-set="true"/>
<type-enum value="3" value-is-set="true"/>
</type>
</types>
Using the same document containing all the permitted values as our source of information to be merged into the form data, we can now develop a stylesheet which performs the above transformation; this stylesheet needs to work on the following principles:
  1. Descend into the form data structure, copying all elements, attributes and text that the stylesheet is not programmed to recognise.
  2. When encountering an item element (which the stylesheet is programmed to recognise), do the following:
    1. Copy the element "skeleton" and its attributes so that the value attribute is retained.
    2. Produce a new types element and process it.
  3. When processing a new types element, do the following:
    1. Add a single type element within it.
    2. Inside this new type element, add the type-enum elements from the document containing the values, and if any type elements were found within the item element, specify these for the activity.
  4. When adding the type-enum elements, if any of them have a value attribute which matches any of the value attributes of the found type elements, set the special value-is-set attribute on that type-enum element.

The stylesheet source code can be found in examples/Common/VerySimple/Resources/structure_multivalue_types.xsl, whereas the document defined above which contains the values can be found in examples/Common/VerySimple/Resources/structure_types.xml.

Updating the Web Resource

To update the special WebStack resource, we now need to modify a few of the class attributes and to add a few others:

    template_resources = {
"structure" : ("structure_multivalue_template.xhtml", "structure_output.xsl")
}
transform_resources = {
"types" : ["structure_multivalue_types.xsl"]
}

With these adjustments, it should now be possible to manipulate the items and subitems whilst specifying multiple type values on each item.