XSLTools

Annotated docs/multiple.html

178:7e7d9dbcec62
2005-07-22 paulb [project @ 2005-07-22 18:26:38 by paulb] Tidied up the function names and added some API documentation. Added child-element and child-attribute functions for coherent references to potentially non-existent nodes in the form data.
paulb@141 1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
paulb@141 2
<html xmlns="http://www.w3.org/1999/xhtml">
paulb@141 3
<head>
paulb@141 4
  <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type" />
paulb@141 5
  <title>Creating Applications: Adding Multiple-Choice Fields and Values</title>
paulb@141 6
  <meta name="generator"
paulb@141 7
 content="amaya 8.1a, see http://www.w3.org/Amaya/" />
paulb@141 8
  <link href="styles.css" rel="stylesheet" type="text/css" />
paulb@141 9
</head>
paulb@141 10
<body>
paulb@141 11
<h1>Creating Applications: Adding Multiple-Choice Fields and Values</h1>
paulb@141 12
<p>Up to this point, we have only considered two kinds of Web form
paulb@141 13
fields: text entry fields and action buttons. Since most Web forms
paulb@141 14
offer more convenient ways of entering certain kinds of data, we shall
paulb@141 15
now investigate multiple-choice fields as an example of how XSLForms
paulb@141 16
handles more complicated types of fields.</p>
paulb@141 17
<p>We shall revise our <a href="data.html">form data structure</a> to
paulb@141 18
be the following:</p>
paulb@141 19
<pre>&lt;?xml version="1.0"?&gt;<br />&lt;structure&gt;<br />  &lt;item value="some value"&gt;<br />    &lt;type value="some type"/&gt;<br />    &lt;subitem subvalue="some other value"/&gt;<br />  &lt;/item&gt;<br />&lt;/structure&gt;</pre>
paulb@141 20
<h2>Single-Valued Fields</h2>
paulb@141 21
<p>Whilst HTML offers types of form fields where users can select one
paulb@141 22
or many values presented in a list or menu, we shall first consider the
paulb@141 23
case where only a single value can be chosen from such a selection.</p>
paulb@145 24
<form method="post" action="" name="single">
paulb@141 25
  <p>Some item:&nbsp;<input name="value" value="some value" /><input
paulb@141 26
 name="remove" value="Remove" type="submit" /></p>
paulb@141 27
  <p>Item type:
paulb@141 28
  <select name="type">
paulb@141 29
  <option>(Not selected)</option>
paulb@141 30
  <option>Important</option>
paulb@141 31
  <option>Not important</option>
paulb@141 32
  <option>Personal</option>
paulb@141 33
  </select>
paulb@141 34
  </p>
paulb@141 35
  <p>Itself containing more items:</p>
paulb@141 36
  <p>Sub-item: <input name="subvalue" value="some other value" /><input
paulb@141 37
 name="remove2" value="Remove" type="submit" /></p>
paulb@141 38
</form>
paulb@141 39
From the&nbsp;item type list only one value may be selected.
paulb@141 40
<p>Taking the&nbsp;example HTML code from before, we can add a
paulb@141 41
definition of this new list to the template to produce something
paulb@141 42
like this:</p>
paulb@144 43
<pre>&lt;html xmlns="http://www.w3.org/1999/xhtml"<br />      xmlns:template="http://www.boddie.org.uk/ns/xmltools/template"&gt;<br />&lt;head&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />&lt;/head&gt;<br />&lt;body template:element="structure"&gt;<br />&lt;form action="" method="POST"&gt;<br /><br />&lt;!-- Template text between the start and the interesting part. --&gt;<br /><br />&lt;div template:element="item"&gt;<br />  &lt;p&gt;<br />    Some item: &lt;input template:attribute="value" name="{template:this-attribute()}" type="text" value="{$this-value}" /&gt;<br />    &lt;input name="remove={template:this-element()}" type="submit" value="Remove" /&gt;<br />  &lt;/p&gt;<br />  <span
paulb@141 44
 style="font-weight: bold;">&lt;p&gt;</span><br
paulb@141 45
 style="font-weight: bold;" /><span style="font-weight: bold;">    Item type:</span><br
paulb@144 46
 style="font-weight: bold;" /><span style="font-weight: bold;">    &lt;select template:element="type" name="{template:new-attribute('value')}"&gt;</span><br
paulb@143 47
 style="font-weight: bold;" /><span style="font-weight: bold;">      &lt;option template:element="type-enum" template:expr="@value = ../@value" template:expr-attr="selected"</span><br
paulb@143 48
 style="font-weight: bold;" /><span style="font-weight: bold;">        template:value="@value" value="{@value}" /&gt;</span><br
paulb@141 49
 style="font-weight: bold;" /><span style="font-weight: bold;">    &lt;/select&gt;</span><br
paulb@144 50
 style="font-weight: bold;" /><span style="font-weight: bold;">  &lt;/p&gt;</span><br />  &lt;p&gt;<br />    Itself containing more items:<br />  &lt;/p&gt;<br />  &lt;p template:element="subitem"&gt;<br />    Sub-item: &lt;input template:attribute="subvalue" name="{template:this-attribute()}" type="text" value="{$this-value}" /&gt;<br />    &lt;input name="remove2={template:this-element()}" type="submit" value="Remove" /&gt;<br />  &lt;/p&gt;<br />  &lt;p&gt;<br />    &lt;input name="add2={template:this-element()}" type="submit" value="Add subitem" /&gt;<br />  &lt;/p&gt;<br />&lt;/div&gt;<br />&lt;p&gt;<br />  &lt;input name="add={template:this-element()}" type="submit" value="Add item" /&gt;<br />&lt;/p&gt;<span
paulb@141 51
 style="font-weight: bold;"><br /><br /></span>&lt;!-- Template text between the interesting part and the end. --&gt;<br /><br />&lt;/form&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;</pre>
paulb@141 52
<p>There are a lot of details here that need to be explained. Here is
paulb@141 53
what was done:</p>
paulb@141 54
<ol>
paulb@141 55
  <li>A paragraph was added to provide some space on the page for the
paulb@141 56
field.</li>
paulb@141 57
  <li>Inside the paragraph, next to the label text, an HTML&nbsp;<code>select</code>
paulb@141 58
element was added.</li>
paulb@141 59
  <li>The&nbsp;<code>select</code> element is mapped onto the&nbsp;<code>type</code>
paulb@141 60
element in the form data structure. However, HTML fields must produce
paulb@141 61
values and it makes no sense to interpret a textual value as an
paulb@141 62
element. Therefore, we indicate in the name of the&nbsp;<code>select</code>
paulb@141 63
element that the value submitted maps onto the&nbsp;<code>value</code>
paulb@141 64
attribute of the&nbsp;<code>type</code> element in the form data
paulb@141 65
structure.</li>
paulb@141 66
  <li>Inside the&nbsp;<code>select</code> element, we include an&nbsp;<code>option</code>
paulb@141 67
element which&nbsp;defines the values which will be presented to users
paulb@141 68
of the form. Note that the&nbsp;<code>option</code> element maps onto
paulb@141 69
a&nbsp;<code>type-enum</code> element which is not mentioned in our
paulb@141 70
revised form data structure above; this will be discussed below.</li>
paulb@141 71
</ol>
paulb@141 72
<h2>Output Structures</h2>
paulb@141 73
<p>Although we revised the form data structure above, and whilst the
paulb@141 74
revised structure can describe form data submitted by users of our
paulb@141 75
application, it is unfortunately not sufficient to define the form data
paulb@141 76
that is to be presented. Consider the multiple-choice values that shall
paulb@141 77
be presented to users: such values are not defined in our revised
paulb@141 78
structure. Therefore, we shall define an output form data structure as
paulb@141 79
follows:</p>
paulb@141 80
<pre>&lt;?xml version="1.0"?&gt;<br />&lt;structure&gt;<br />  &lt;item value="some value"&gt;<br />    &lt;type value="some type"&gt;<br />      &lt;type-enum value="choice #n"/&gt;<br />    &lt;/type&gt;<br />    &lt;subitem subvalue="some other value"/&gt;<br />  &lt;/item&gt;<br />&lt;/structure&gt;</pre>
paulb@148 81
<h3>Presenting the Extra Values</h3>
paulb@148 82
<p>In the template, the&nbsp;<code>option</code> element is presented
paulb@148 83
using a number of special annotations which make more sense when
paulb@148 84
considering the above output structure:</p>
paulb@148 85
<ul>
paulb@148 86
  <li>The&nbsp;<code>template:element</code> annotation states that the
paulb@148 87
    <code>option</code> element maps into the&nbsp;<code>type-enum</code>
paulb@148 88
element, meaning that each&nbsp;<code>type-enum</code> element will be
paulb@148 89
reproduced as an option inside the list or menu presented in the Web
paulb@148 90
form.</li>
paulb@148 91
  <li>The&nbsp;<code>template:value</code> annotation states that the
paulb@148 92
contents of&nbsp;the <code>option</code> element will correspond to
paulb@148 93
the value of the&nbsp;<code>type-enum</code> element's&nbsp;<code>value</code>
paulb@148 94
attribute - the notation employed here actually belongs to XSL.</li>
paulb@148 95
  <li>The&nbsp;<code>template:expr</code> and&nbsp;<code>template:expr-attr</code>
paulb@148 96
annotations work together and state that...<br />
paulb@148 97
    <ol>
paulb@148 98
      <li>When the expression in <code>template:expr</code> is true...</li>
paulb@148 99
      <li>The attribute in <code>template:expr-attr</code> will be
paulb@148 100
added to the <code>option</code> element with a value identical to its
paulb@148 101
name.</li>
paulb@148 102
    </ol>
paulb@148 103
  </li>
paulb@148 104
  <li>The <code>value</code> attribute is defined to reproduce
paulb@148 105
the&nbsp;<code>value</code> attribute from the&nbsp;<code>type-enum</code>
paulb@148 106
element - the notation employed here belongs, once again, to XSL.</li>
paulb@148 107
</ul>
paulb@148 108
<p>The result of this is that the&nbsp;<code>type</code> element in the
paulb@148 109
this example&nbsp;structure fragment...</p>
paulb@148 110
<pre>&lt;type value="2"&gt;<br />  &lt;type-enum value="1"/&gt;<br />  &lt;type-enum value="2"/&gt;<br />  &lt;type-enum value="3"/&gt;<br />&lt;/type&gt;</pre>
paulb@148 111
<p>...is transformed into something resembling this HTML code:</p>
paulb@148 112
<pre>&lt;select name="..."&gt;<br />  &lt;option value="1"&gt;1&lt;/option&gt;<br />  &lt;option value="2" selected="selected"&gt;2&lt;/option&gt;<br />  &lt;option value="3"&gt;3&lt;/option&gt;<br />&lt;/select&gt;</pre>
paulb@148 113
<p>Such presentation techniques are sufficient if the input form data
paulb@148 114
structure is identical to the output structure, but since we will
paulb@148 115
receive a structure resembling that defined
paulb@148 116
earlier (where the multiple-choice values are never sent back to the
paulb@148 117
application), yet need to present a structure like the one above, we
paulb@148 118
will
paulb@141 119
need to find a way of merging the range of allowed values into the
paulb@141 120
user-edited form data before presenting that data using our template.</p>
paulb@148 121
<h2>Merging Values into the Form Data</h2>
paulb@148 122
<p>There are many possible ways of inserting extra XML elements into an
paulb@148 123
existing XML document, but we shall concentrate on using an XSL
paulb@148 124
stylesheet to perform this merge operation. First, let us define a
paulb@148 125
document containing all the possible values for the type field:</p>
paulb@148 126
<pre>&lt;?xml version="1.0"?&gt;<br />&lt;types&gt;<br />  &lt;type-enum value="(Not selected)"/&gt;<br />  &lt;type-enum value="Important"/&gt;<br />  &lt;type-enum value="Not important"/&gt;<br />  &lt;type-enum value="Personal"/&gt;<br />&lt;/types&gt;</pre>
paulb@148 127
<p>We shall refer to this document when inserting the different&nbsp;<code>type-enum</code>
paulb@148 128
elements into our input form data structure to produce the output
paulb@148 129
structure described above. The stylesheet which performs this task is
paulb@148 130
quite scary for those not familiar with XSL, but it works on the
paulb@148 131
following principles:</p>
paulb@148 132
<ol>
paulb@148 133
  <li>Descend into the form data structure, copying all elements,
paulb@148 134
attributes and text that the stylesheet is not programmed to recognise.</li>
paulb@148 135
  <li>When encountering an&nbsp;<code>item</code> element (which the
paulb@148 136
stylesheet is programmed to recognise), do the following:<br />
paulb@148 137
    <ol>
paulb@148 138
      <li>Copy the&nbsp;element "skeleton" and its attributes so that
paulb@148 139
the&nbsp;<code>value</code> attribute is retained.</li>
paulb@157 140
      <li>Make&nbsp;a&nbsp;<code>type</code> element inside the&nbsp;<code>item</code>
paulb@157 141
element and process it.</li>
paulb@148 142
    </ol>
paulb@148 143
  </li>
paulb@148 144
  <li>When processing a new&nbsp;<code>type</code> element, do the
paulb@148 145
following:<br />
paulb@148 146
    <ol>
paulb@157 147
      <li>Copy the attributes of any existing&nbsp;<code>type</code>
paulb@157 148
element so that
paulb@157 149
the&nbsp;<code>value</code> attribute is retained.</li>
paulb@148 150
      <li>Add the&nbsp;<code>type-enum</code> elements from the
paulb@148 151
document defined above.</li>
paulb@148 152
    </ol>
paulb@148 153
  </li>
paulb@148 154
</ol>
paulb@148 155
<p>The stylesheet source code can be found in&nbsp;<code>examples/Common/VerySimple/Resources/structure_types.xsl</code>,
paulb@148 156
whereas the document defined above which contains the values can be
paulb@148 157
found in <code>examples/Common/VerySimple/Resources/structure_types.xml</code>.</p>
paulb@148 158
<h3>Performing the Merge</h3>
paulb@148 159
<p>To take advantage of these new documents, it is necessary to
paulb@148 160
introduce some code into the Web resource to perform the merge
paulb@148 161
operation. The special WebStack resource that we <a
paulb@148 162
 href="Web-resource.html">subclassed earlier</a> provides some
paulb@148 163
convenient mechanisms for introducing XSL-based transformations, and we
paulb@148 164
shall add a few extra attributes to our resource class in order to take
paulb@148 165
advantage of them:</p>
paulb@148 166
<pre>    # Under template_resources...<br /><br />    transform_resources = {<br />        "types" : ["structure_types.xsl"]<br />        }<br />    document_resources = {<br />        "types" : "structure_types.xml"<br />        }</pre>
paulb@148 167
<p>These attributes define the following things:</p>
paulb@148 168
<ol>
paulb@148 169
  <li>A transformation called&nbsp;<code>types</code> which uses
paulb@148 170
the&nbsp;<code>structure_types.xsl</code> stylesheet file.</li>
paulb@148 171
  <li>A document referred to by the name&nbsp;<code>types</code> which
paulb@148 172
is provided by the&nbsp;<code>structure_types.xml</code> file.</li>
paulb@148 173
</ol>
paulb@148 174
<p>To actually perform the merge operation, we need to add a few extra
paulb@148 175
lines of code after the addition and deletion operations in the&nbsp;<code>respond_to_form</code>
paulb@148 176
method:</p>
paulb@148 177
<pre>        # Under the addition and deletion operations...<br /><br />        # Transform, adding enumerations/ranges.<br /><br />        types_xsl_list = self.prepare_transform("types")<br />        types_xml = self.prepare_document("types")<br />        structure = self.get_result(types_xsl_list, structure, references={"types" : types_xml})<br /><br />        # Start the response.</pre>
paulb@148 178
<p>These lines do the following things:</p>
paulb@148 179
<ol>
paulb@148 180
  <li>Obtain the stylesheets for the&nbsp;<code>types</code>
paulb@148 181
transformation.</li>
paulb@148 182
  <li>Obtain the&nbsp;<code>types</code>&nbsp;document containing the
paulb@148 183
values to be merged into the form data.</li>
paulb@148 184
  <li>Take the stylesheets and apply them to the form data,&nbsp;<code>structure</code>,
paulb@148 185
using a reference to the&nbsp;<code>types</code> document containing
paulb@148 186
the values.</li>
paulb@148 187
</ol>
paulb@148 188
<p>The result of this should be a processed&nbsp;<code>structure</code>
paulb@148 189
document containing the type values for each&nbsp;<code>type</code>
paulb@148 190
element in that document.</p>
paulb@148 191
<h2>Other Multiple-Choice Data</h2>
paulb@148 192
<p>We have now added a simple, single-valued multiple-choice field to
paulb@148 193
the application. However, many applications often need to obtain <a
paulb@151 194
 href="multivalue.html">multivalued multiple-choice data</a>, and this
paulb@148 195
kind of information is investigated in the next part of the development
paulb@148 196
<a href="overview.html">process</a>.</p>
paulb@141 197
</body>
paulb@141 198
</html>