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">
<type>
<type-enum value="some type"/>
<type-enum value="some other type"/>
</type>
<subitem subvalue="some other value"/>
</item>
</structure>
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.
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>
Item type:
<select template:element="type" name="{template:list-attribute('type-enum', '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:
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-enum
element is created (inside the type
element) with a value
attribute containing that value.select
element now has a multiple
attribute defined to permit multiple value selections.select
element, the option
element mapping onto
a type-enum
element using a different template:expr
condition than was used before.Unlike in the single-valued case, the revised the form data structure for input is almost the same as the structure used by the template. Indeed, the subtle differences cannot be represented in our simplistic presentation of the structure:
<?xml version="1.0"?>
<structure>
<item value="some value">
<type>
<type-enum value="some type"/>
<type-enum value="some other type"/>
</type>
<subitem subvalue="some other value"/>
</item>
</structure>
In fact, the principal difference arises through the number of type-enum
elements that occur in the input, representing the values selected by
the user, and the number that occur in the output, representing the
complete range of values available for selection.
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 type
element in the
this example structure fragment...
<type>
<type-enum value="1"/>
<type-enum value="2" value-is-set="true"/>
<type-enum value="3" value-is-set="true"/>
</type>
...is transformed into something resembling this HTML code:
<select name="..." multiple="multiple">
<option value="1">1</option>
<option value="2" selected="selected">2</option>
<option value="3" selected="selected">3</option>
</select>
One principal issue arises when considering the above
transformation: where does the special value-is-set
attribute
come from?
type-enum
elements into the type
element, we would lose track of which values were selected. Therefore,
we need to employ a different strategy in remembering those values than
that of assuming that those type-enum
elements which
are present are those which are selected.
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 mark the selected values in the
entire list of type-enum
elements in order to
distinguish them from the values which are not selected. In other
words, we want to turn
something like this...
<type>
<type-enum value="2"/>
<type-enum value="3"/>
</type>
...into something like this:
<type>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:
<type-enum value="1"/>
<type-enum value="2" value-is-set="true"/>
<type-enum value="3" value-is-set="true"/>
</type>
item
element (which the
stylesheet is programmed to recognise), do the following:value
attribute is retained.type
element and process it.type
element, do the
following:type
element, add the type-enum
elements from the
values document, and if any type-enum
elements were found within an existing type
element from
the form data, specify
these for the activity.type-enum
elements, if any of
them have a value
attribute which matches any of the value
attributes of the found type-enum
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
.
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.
Note that it may be necessary to remove the old stylesheet for
producing output, structure_output.xsl
, so that the
multivalue version of the template is taken into use.
Now that we have designed and implemented a simple application, it may be worth reading some recommendations about developing your own applications.