To avoid hard-to-explain problems when designing and testing templates, the following advice may be of some use:
It is not necessarily a good idea to nest elements inside multiple-choice elements like this:
<multi>
<multi-enum value="1"/>
<multi-enum value="2"/>
<multi-enum value="3"/>
<nested value="x"/>
</multi>
The reason for this is that the number of multiple-choice values may vary within your application, and the nested elements will appear at a different position depending on how many such values have been inserted. Whilst this might not affect some applications, at least not to begin with, the usage of more advanced features (in-page updates, for example) will probably expose problems due to the way XSLForms reconstructs the XML document data from the input form data.
We can avoid the above mistake by specifying the first parameter in the template:multiple-choice-field
and template:multiple-choice-list-field
annotations. For example:
<select name="..." template:multiple-choice-field="multi,multi-enum,value">
<option value="..." template:multiple-choice-value="multi-enum,value,selected"></option>
</select>
This effectively prevents us from inserting the nested
element inside the multi
element.
Although we ignore this rule with the example in this documentation, it is necessary to be aware of problems with adding and removing elements where other elements may reside. Consider part of our form data structure:
<item value="a">
<type>
<type-enum value="1"/>
</type>
<subitem value="x"/>
</item>
Provided that we control the process of adding and removing the
elements, making sure that they always reside at the end of the element
collection inside the item
element, and that they
always follow a known number of elements, we can avoid issues with more
advanced features (in-page updates,
for example), although using such features on the subitem
elements themselves may cause problems that may only be resolved by
moving the subitem
elements into a container element
of their own:
<item value="a">
<type>
<type-enum value="1"/>
</type>
<subitems>
<subitem value="x"/>
</subitems>
</item>
Since XSLForms templates essentially describe the presentation of an XML document, it is vital that the output form data structure agrees with the template - that is, the output structure can be properly processed by the template and that all parts of the template are displayed as expected. It is also very important to make sure that transformations on the input document produce all the necessary elements for the output document so that the resulting page gives the user the opportunity to specify data that is missing. Consider this section of an example template:
<p template:element="package">
<p template:element="author">
Name: <input template:attribute-field="name" name="..." type="text" value="..."/>
</p>
</p>
Here, if the author
element is not found in the
output structure, no field will be produced in the Web page, no
opportunity will be given for an author to be specified, and no author
information will subsequently be editable. One solution is to introduce
the author
element into the XML document when
creating the package
element - this should then
"bootstrap" the process and ensure that the author details will remain
editable as long as the package
element exists.
Although it is not necessary to use document initialisation in resources, the above case would be detected by an input/initialiser stylesheet, and the package
and author
elements would be added if no way of adding them was mentioned in the template. Typically, we would employ selectors to provide the ability to add elements in templates, and the above example could be extended as follows:
<p template:element="package">
<p template:element="author">
Name: <input template:attribute-field="name" name="..." type="text" value="..."/>
</p>
<p>
<input name="..." template:selector-field="add-author,author" type="submit" value="Add author" />
</p>
</p>
With the newly-added selector, we can see that author
elements could at least be added by users of the application, but package
elements would still be impossible to create in the user interface. The
document initialisation mechanism distinguishes between these two cases
by looking for selectors which mention element names; here, the template:selector-field
attribute has two parts to its value:
author
Since the author
element is mentioned, the mechanism knows not to create such elements
automatically. However, since no such selector exists for package
elements, those elements are created automatically.
After
document initialisation or any other transformation, it is necessary to
re-evaluate selector information in the context of the updated document
if such information is to be used with such updated data, noting that
any changes in the structure of the such data will cause the selectors
to refer to the wrong parts of documents. To make updated documents
available to XSLForms, the following call can be made on the form
object (the third parameter in the respond_to_form
method):
form.set_document(document_name, updated_document)
The updated selectors can then be obtained as usual:
selectors = form.get_selectors()
Typically, selectors should be accessed and used before initialisation since they refer to information that must already exist and can therefore be manipulated without preparatory work being done on the documents involved.