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><?xml version="1.0"?><br /><structure><br /> <item value="some value"><br /> <type value="some type"/><br /> <subitem subvalue="some other value"/><br /> </item><br /></structure></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: <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 item type list only one value may be selected. |
paulb@141 | 40 | <p>Taking the 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><html xmlns="http://www.w3.org/1999/xhtml"<br /> xmlns:template="http://www.boddie.org.uk/ns/xmltools/template"><br /><head><br /> <title>Example</title><br /></head><br /><body template:element="structure"><br /><form action="" method="POST"><br /><br /><!-- Template text between the start and the interesting part. --><br /><br /><div template:element="item"><br /> <p><br /> Some item: <input template:attribute="value" name="{template:this-attribute()}" type="text" value="{$this-value}" /><br /> <input name="remove={template:this-element()}" type="submit" value="Remove" /><br /> </p><br /> <span |
paulb@141 | 44 | style="font-weight: bold;"><p></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;"> <select template:element="type" name="{template:new-attribute('value')}"></span><br |
paulb@143 | 47 | style="font-weight: bold;" /><span style="font-weight: bold;"> <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}" /></span><br |
paulb@141 | 49 | style="font-weight: bold;" /><span style="font-weight: bold;"> </select></span><br |
paulb@144 | 50 | style="font-weight: bold;" /><span style="font-weight: bold;"> </p></span><br /> <p><br /> Itself containing more items:<br /> </p><br /> <p template:element="subitem"><br /> Sub-item: <input template:attribute="subvalue" name="{template:this-attribute()}" type="text" value="{$this-value}" /><br /> <input name="remove2={template:this-element()}" type="submit" value="Remove" /><br /> </p><br /> <p><br /> <input name="add2={template:this-element()}" type="submit" value="Add subitem" /><br /> </p><br /></div><br /><p><br /> <input name="add={template:this-element()}" type="submit" value="Add item" /><br /></p><span |
paulb@141 | 51 | style="font-weight: bold;"><br /><br /></span><!-- Template text between the interesting part and the end. --><br /><br /></form><br /></body><br /></html></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 <code>select</code> |
paulb@141 | 58 | element was added.</li> |
paulb@141 | 59 | <li>The <code>select</code> element is mapped onto the <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 <code>select</code> |
paulb@141 | 63 | element that the value submitted maps onto the <code>value</code> |
paulb@141 | 64 | attribute of the <code>type</code> element in the form data |
paulb@141 | 65 | structure.</li> |
paulb@141 | 66 | <li>Inside the <code>select</code> element, we include an <code>option</code> |
paulb@141 | 67 | element which defines the values which will be presented to users |
paulb@141 | 68 | of the form. Note that the <code>option</code> element maps onto |
paulb@141 | 69 | a <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><?xml version="1.0"?><br /><structure><br /> <item value="some value"><br /> <type value="some type"><br /> <type-enum value="choice #n"/><br /> </type><br /> <subitem subvalue="some other value"/><br /> </item><br /></structure></pre> |
paulb@148 | 81 | <h3>Presenting the Extra Values</h3> |
paulb@148 | 82 | <p>In the template, the <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 <code>template:element</code> annotation states that the |
paulb@148 | 87 | <code>option</code> element maps into the <code>type-enum</code> |
paulb@148 | 88 | element, meaning that each <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 <code>template:value</code> annotation states that the |
paulb@148 | 92 | contents of the <code>option</code> element will correspond to |
paulb@148 | 93 | the value of the <code>type-enum</code> element's <code>value</code> |
paulb@148 | 94 | attribute - the notation employed here actually belongs to XSL.</li> |
paulb@148 | 95 | <li>The <code>template:expr</code> and <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 <code>value</code> attribute from the <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 <code>type</code> element in the |
paulb@148 | 109 | this example structure fragment...</p> |
paulb@148 | 110 | <pre><type value="2"><br /> <type-enum value="1"/><br /> <type-enum value="2"/><br /> <type-enum value="3"/><br /></type></pre> |
paulb@148 | 111 | <p>...is transformed into something resembling this HTML code:</p> |
paulb@148 | 112 | <pre><select name="..."><br /> <option value="1">1</option><br /> <option value="2" selected="selected">2</option><br /> <option value="3">3</option><br /></select></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><?xml version="1.0"?><br /><types><br /> <type-enum value="(Not selected)"/><br /> <type-enum value="Important"/><br /> <type-enum value="Not important"/><br /> <type-enum value="Personal"/><br /></types></pre> |
paulb@148 | 127 | <p>We shall refer to this document when inserting the different <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 <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 element "skeleton" and its attributes so that |
paulb@148 | 139 | the <code>value</code> attribute is retained.</li> |
paulb@157 | 140 | <li>Make a <code>type</code> element inside the <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 <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 <code>type</code> |
paulb@157 | 148 | element so that |
paulb@157 | 149 | the <code>value</code> attribute is retained.</li> |
paulb@148 | 150 | <li>Add the <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 <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 <code>types</code> which uses |
paulb@148 | 170 | the <code>structure_types.xsl</code> stylesheet file.</li> |
paulb@148 | 171 | <li>A document referred to by the name <code>types</code> which |
paulb@148 | 172 | is provided by the <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 <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 <code>types</code> |
paulb@148 | 181 | transformation.</li> |
paulb@148 | 182 | <li>Obtain the <code>types</code> 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, <code>structure</code>, |
paulb@148 | 185 | using a reference to the <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 <code>structure</code> |
paulb@148 | 189 | document containing the type values for each <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> |