# HG changeset patch # User paulb # Date 1128380727 0 # Node ID 2fa5fb4ba21a2513294ed3e341298a7d4d73516e # Parent 6e64e6d7aea004c5f568e70b49643ee1c192fda5 [project @ 2005-10-03 23:05:27 by paulb] Updated the documentation to describe the updated VerySimple example, along with "macro" attributes. diff -r 6e64e6d7aea0 -r 2fa5fb4ba21a docs/Web-resource.html --- a/docs/Web-resource.html Mon Oct 03 23:04:48 2005 +0000 +++ b/docs/Web-resource.html Mon Oct 03 23:05:27 2005 +0000 @@ -1,23 +1,18 @@ - - + - Creating Applications: Write a Web Resource - - - + + Creating Applications: Write a Web Resource +

Creating Applications: Write a Web Resource

With a completed template after the design, -structure annotation and selector annotation, we may now write a Web +structure annotation and selector annotation, we may now write a Web resource which will expose our form as a Web application, allowing users to input information and to manipulate that information using their Web browser. Whilst XSLForms is just a normal Python package which can be used from many kinds of programs and environments, we -shall concentrate on using the built-in WebStack +shall concentrate on using the built-in WebStack support to build a WebStack application around our form template.

XSLForms Meets WebStack

@@ -59,12 +54,9 @@ is automatically produced from the template, we only need to choose a name which is not already in use by another file, and for clarity a name similar to that of the template is recommended: structure_output.xsl - - - +

The class also has a method which resembles the typical respond -method of normal WebStack +method of normal WebStack resources: the respond_to_form method is, in fact, a special version of that method providing ready-to-use information about the form (or forms) being edited.

@@ -139,7 +131,5 @@

We should now have an application which can be deployed and tested using the usual WebStack techniques. However, more advanced templates can be designed, and we shall consider multiple-choice -fields in the next activity in the development process.

- - +fields in the next activity in the development process.

+ \ No newline at end of file diff -r 6e64e6d7aea0 -r 2fa5fb4ba21a docs/advice.html --- a/docs/advice.html Mon Oct 03 23:04:48 2005 +0000 +++ b/docs/advice.html Mon Oct 03 23:05:27 2005 +0000 @@ -1,12 +1,10 @@ - - + - Creating Applications: Recommendations and Advice - - - + + Creating Applications: Recommendations and Advice + +

Creating Applications: Recommendations and Advice

    @@ -21,8 +19,7 @@ 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 +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.

    @@ -54,7 +51,7 @@ 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="name" name="{template:this-attribute()}" type="text" value="{$this-value}"/>
    </p>
    </p>
    +
    <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 @@ -62,8 +59,10 @@ 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.

    +editable as long as the package element exists.

    Ensuring Element Structure with Document Initialisation

    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:

    1. A name used to identify the selector.
    2. The name of an element: 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.

    - - + \ No newline at end of file diff -r 6e64e6d7aea0 -r 2fa5fb4ba21a docs/in-page-updates.html --- a/docs/in-page-updates.html Mon Oct 03 23:04:48 2005 +0000 +++ b/docs/in-page-updates.html Mon Oct 03 23:05:27 2005 +0000 @@ -1,12 +1,10 @@ - - + - Creating Applications: In-Page Updates - - - + + Creating Applications: In-Page Updates + +

    Creating Applications: In-Page Updates

    One fashionable avenue in Web application design has been that of @@ -16,33 +14,26 @@ such "in-page" or "live" updates.

    Consider the addition of a comment field to our application. Here is how the HTML code might look:

    -
    <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 template:element="options">
    <span template:element="comment">Comment:
    <textarea template:attribute="value" name="{template:this-attribute()}" cols="40" rows="3">
    <span template:value="$this-value" template:effect="replace">Some comment</span>
    </textarea>
    </span>
    </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>
    -

    The newly-added textarea field will not be -presented in the application in its current state; this is due to the -lack of any options or comment elements +

    <div template:element="item">
    <p>
    Some item: <input template:attribute-field="value" name="..." type="text" value="..." />
    <input name="..." template:selector-field="remove" type="submit" value="Remove" />
    </p>
    <p>
    Item type:
    <select template:multiple-choice-list-field="type,type-enum,value" name="..." multiple="multiple">
    <option template:multiple-choice-list-value="type-enum,value,selected" value="..." />
    </select>
    </p>
    <p template:element="options">
    <span template:element="comment">Comment:
    <textarea template:attribute-area="value,insert" name="..." cols="40" rows="3">
    Some comment
    </textarea>
    </span>
    </p>
    <p>
    Itself containing more items:
    </p>
    <p template:element="subitem">
    Sub-item: <input template:attribute-field="subvalue" name="..." type="text" value="..." />
    <input name="..." template:selector-field="remove2" type="submit" value="Remove" />
    </p>
    <p>
    <input name="..." template:selector-field="add2,subitem" type="submit" value="Add subitem" />
    </p>
    </div>
    +

    Here, a textarea element has been added with a special template:attribute-area annotation being used to state that the contents of the element are to be mapped to the value attribute, and that the attribute contents are to be inserted inside the textarea element (replacing the Some Comment text).

    The newly-added textarea field might actually be +presented in the application in its current state, despite the lack of any options or comment +elements manipulated by the -application, and such template changes are actually quite safe to make. -So, we must now do some additional work to add such options -and comment -elements in our application.

    -

    One approach is to extend our transformation which adds the -different type values so that these new elements are -introduced as well. In the Web resource, we can make the following -change:

    -
        transform_resources = {
    "types" : ["structure_multivalue_types.xsl", "structure_comments.xsl"]
    }
    -

    What this does is to state that when we carry out the types -transformation, two stylesheets are employed, one before the other, -such that the type values are first added using the first stylesheet -(and the additional reference document containing the type values) and -that the comments are then added using the second stylesheet.

    +application, due to the document initialisation mechanism employed by +the application. However, what would be more interesting is the +possibility of only showing the comment field if something else in the +document had a certain value or state.

    +

    Let us imagine that if the type of an item was set to "Personal", +the comment field would appear and permit the recording of some text +for that item. One approach that would make this possible is to +add a transformation which checks the type values set for each of the +items and removes the options and comment elements for items which do not qualify. In the Web resource, we make the following +changes:

    +
        transform_resources = {
    "comments" : ["structure_comments.xsl"]
    }
    +

    What this does is to state that when we carry out the comments +transformation, the specified stylesheet is employed, filtering out the +comments for non-qualifying items and preserving them for qualifying +items.

    Further down in the code, we add a transformation:

            # After the document initialisation...

    # Add the comments.

    comments_xsl_list = self.prepare_transform("comments")
    structure = self.get_result(comments_xsl_list, structure)

    This new stylesheet works according to the following principles:

    1. Descend into the form data structure, copying all elements, @@ -67,9 +58,8 @@
-

Since this stylesheet is used after the type value transformation, -we may (and even must) take advantage of the results of that -transformation, including noting that selected values on type-enum +

Since this stylesheet is used after the document initialisation, +we may (and even must) take advantage of the results of that activity, including noting that selected values on type-enum elements are marked with the value-is-set attribute.

The stylesheet source code can be found in examples/Common/VerySimple/Resources/structure_comments.xsl.

Limitations and Enhancements

@@ -90,9 +80,7 @@ can be added and removed, regardless of whether such a field existed there before. The above template code needs modifying slightly to permit this:

-
  <p template:element="options" template:id="comment-node" id="{template:this-element()}">
<span template:element="comment">Comment:
<textarea template:attribute="value" name="{template:this-attribute()}" cols="40" rows="3">
<span template:value="$this-value" template:effect="replace">Some comment</span>
</textarea>
</span>
</p>
+
  <p template:element="options" template:id="comment-node" id="{template:this-element()}">
<span template:element="comment">Comment:
<textarea template:attribute-area="value,insert" name="..." cols="40" rows="3">
Some comment
</textarea>
</span>
</p>

Here, we have added this region definition to the paragraph surrounding the comment field, annotating the paragraph with the following attributes:

@@ -119,21 +107,13 @@

Since we rely on JavaScript support in the browser, the following references to scripts must also be added to the template, as shown in the following excerpt:

-
<head>
<title>Example</title>
<script type="text/javascript" src="scripts/sarissa.js"> </script>
<script type="text/javascript" src="scripts/XSLForms.js"> </script>
</head>
+
<head>
<title>Example</title>
<script type="text/javascript" src="scripts/sarissa.js"> </script>
<script type="text/javascript" src="scripts/XSLForms.js"> </script>
</head>

These special script files can be found in examples/Common/VerySimple/Resources/scripts.

Now we can concentrate on adding the event which triggers an in-page update. Since it is the type values that cause each comment field to be added or removed, we add an event attribute on the form field responsible for displaying the type values:

-
  <p>
Item type:
<select template:element="type" name="{template:list-attribute('type-enum', 'value')}" multiple="multiple"
onchange="requestUpdate(
'comments',
'{template:list-attribute('type-enum', 'value')}',
'{template:other-elements(../options)}',
'{template:child-attribute('value', template:child-element('comment', 1, template:other-elements(../options)))}',
'/structure/item/options')">
<option template:element="type-enum" template:expr="@value-is-set" template:expr-attr="selected"
template:value="@value" value="{@value}" />
</select>
</p>
+
  <p>
Item type:
<select template:multiple-choice-list-field="type,type-enum,value" name="..." multiple="multiple"
onchange="requestUpdate(
'comments',
'{template:list-attribute('type-enum', 'value')}',
'{template:other-elements(../options)}',
'{template:child-attribute('value', template:child-element('comment', 1, template:other-elements(../options)))}',
'/structure/item/options')">
<option template:multiple-choice-list-value="type-enum,value,selected" value="..." />
</select>
</p>

This complicated string calls a special update request JavaScript function which triggers the in-page update, and it specifies the following things:

@@ -190,17 +170,10 @@ pages from our application. Some standard WebStack resources can be used to help with this, and we add some imports at the top of our source file:

-
#!/usr/bin/env python

"A very simple example application."

import WebStack.Generic
import XSLForms.Resources
import XSLForms.Utils
import os

# Site map imports.

from WebStack.Resources.ResourceMap import MapResource
from WebStack.Resources.Static import DirectoryResource
+
#!/usr/bin/env python

"A very simple example application."

import WebStack.Generic
import XSLForms.Resources
import XSLForms.Utils
import os

# Site map imports.

from WebStack.Resources.ResourceMap import MapResource
from WebStack.Resources.Static import DirectoryResource

Then, we define the resource class as before, but with an additional attribute:

-
# Resource classes.

class VerySimpleResource(XSLForms.Resources.XSLFormsResource):

"A very simple resource providing a hierarchy of editable fields."

resource_dir = os.path.join(os.path.split(__file__)[0], "Resources")
encoding = "utf-8"
template_resources = {
"structure" : ("structure_multivalue_template.xhtml", "structure_output.xsl")
}
transform_resources = {
"types" : ["structure_multivalue_types.xsl", "structure_comments.xsl"]
}
document_resources = {
"types" : "structure_types.xml"
}
in_page_resources = {
"comments" : ("structure_output_comments.xsl", "comment-node")
}
+
# Resource classes.

class VerySimpleResource(XSLForms.Resources.XSLFormsResource):

"A very simple resource providing a hierarchy of editable fields."

resource_dir = os.path.join(os.path.split(__file__)[0], "Resources")
encoding = "utf-8"
template_resources = {
"structure" : ("structure_multivalue_template.xhtml", "structure_output.xsl")
}
init_resources = {
"structure" : ("structure_multivalue_template.xhtml", "structure_input.xsl")
}
transform_resources = {
"comments" : ["structure_comments.xsl"]
}
document_resources = {
"types" : "structure_types.xml"
}
in_page_resources = {
"comments" : ("structure_output_comments.xsl", "comment-node")
}

This new attribute provides information about the in-page request to retrieve comment regions of the Web form, and it consists of the stylesheet filename that will be generated to produce the page @@ -208,31 +181,17 @@ we defined above.

The respond_to_form method now also includes some additional code:

-
    def respond_to_form(self, trans, form):

"""
Respond to a request having the given transaction 'trans' and the given
'form' information.
"""

in_page_resource = self.get_in_page_resource(trans)
parameters = form.get_parameters()
documents = form.get_documents()
+
    def respond_to_form(self, trans, form):

"""
Respond to a request having the given transaction 'trans' and the given
'form' information.
"""

in_page_resource = self.get_in_page_resource(trans)
parameters = form.get_parameters()
documents = form.get_documents()

Here, we find out whether an in-page update is requested, along with the raw parameters of the request, some of which will be used later on in the method.

The discovery of the form data structure and the addition and removal of elements happens as before, as does the merging of type values and the comment field, if applicable:

-
        # Ensure the presence of a document.

if documents.has_key("structure"):
structure = documents["structure"]
else:
structure = form.new_instance("structure")

# Add and remove elements according to the selectors found.

selectors = form.get_selectors()
XSLForms.Utils.remove_elements(selectors.get("remove2"))
XSLForms.Utils.add_elements(selectors.get("add2"), "subitem")
XSLForms.Utils.remove_elements(selectors.get("remove"))
XSLForms.Utils.add_elements(selectors.get("add"), "item")

# Transform, adding enumerations/ranges.

types_xsl_list = self.prepare_transform("types")
types_xml = self.prepare_document("types")
structure = self.get_result(types_xsl_list, structure, references={"types" : types_xml})
+
        # Ensure the presence of a document.

if documents.has_key("structure"):
structure = documents["structure"]
else:
structure = form.new_instance("structure")

# Add and remove elements according to the selectors found.

selectors = form.get_selectors()
XSLForms.Utils.remove_elements(selectors.get("remove2"))
XSLForms.Utils.add_elements(selectors.get("add2"), "subitem")
XSLForms.Utils.remove_elements(selectors.get("remove"))
XSLForms.Utils.add_elements(selectors.get("add"), "item")

# Initialise the document, adding enumerations/ranges.

structure_xsl = self.prepare_initialiser("structure")
types_xml = self.prepare_document("types")
structure = self.get_result([structure_xsl], structure, references={"type" : types_xml})

# Add the comments.

comments_xsl_list = self.prepare_transform("comments")
structure = self.get_result(comments_xsl_list, structure)

The significant changes begin when presenting the result of the request processing:

-
        # Start the response.

trans.set_content_type(WebStack.Generic.ContentType("application/xhtml+xml", self.encoding))

# Define the stylesheet parameters.

stylesheet_parameters = {}

# Ensure that an output stylesheet exists.

if in_page_resource in self.in_page_resources.keys():
trans_xsl = self.prepare_fragment("structure", in_page_resource)
element_path = parameters.get("element-path", [""])[0]
stylesheet_parameters["element-path"] = element_path
else:
trans_xsl = self.prepare_output("structure")
+
        # Start the response.

trans.set_content_type(WebStack.Generic.ContentType("application/xhtml+xml", self.encoding))

# Define the stylesheet parameters.

stylesheet_parameters = {}

# Ensure that an output stylesheet exists.

if in_page_resource in self.in_page_resources.keys():
trans_xsl = self.prepare_fragment("structure", in_page_resource)
element_path = parameters.get("element-path", [""])[0]
stylesheet_parameters["element-path"] = element_path
else:
trans_xsl = self.prepare_output("structure")

Instead of just obtaining a stylesheet for the structure document, we instead check to see if an in-page update is being requested and, if so, prepare the stylesheet representing the fragment @@ -242,33 +201,12 @@ stylesheet when making the final Web page output.

Finally, we send the output to the user but employing the additional stylesheet parameters to configure the result:

-
        # Complete the response.

self.send_output(trans, [trans_xsl], structure, stylesheet_parameters)
+
        # Complete the response.

self.send_output(trans, [trans_xsl], structure, stylesheet_parameters)

In order to introduce the infrastructure mentioned above which separates requests for Web pages from requests for JavaScript files, we need to provide a more sophisticated implementation of the get_site function:

-
# Site map initialisation.

def get_site():

"Return a simple Web site resource."

# Get the main resource and the directory used by the application.

very_simple_resource = VerySimpleResource()
directory = very_simple_resource.resource_dir

# Make a simple Web site.

resource = MapResource({
# Static resources:
"scripts" : DirectoryResource(os.path.join(directory, "scripts"), {"js" : "text/javascript"}),
# Main page and in-page resources:
None : very_simple_resource
})

return resource
+
# Site map initialisation.

def get_site():

"Return a simple Web site resource."

# Get the main resource and the directory used by the application.

very_simple_resource = VerySimpleResource()
directory = very_simple_resource.resource_dir

# Make a simple Web site.

resource = MapResource({
# Static resources:
"scripts" : DirectoryResource(os.path.join(directory, "scripts"), {"js" : "text/javascript"}),
# Main page and in-page resources:
None : very_simple_resource
})

return resource

What this does is to create a resource for the application, as before, but then to place the resource into a special WebStack resource which examines the path or URL on the incoming requests and directs @@ -285,5 +223,4 @@ script file; otherwise it gets a Web page showing either all of the form (if a normal request is received), or a part of the form (if an in-page request is received).

- - + \ No newline at end of file diff -r 6e64e6d7aea0 -r 2fa5fb4ba21a docs/multiple.html --- a/docs/multiple.html Mon Oct 03 23:04:48 2005 +0000 +++ b/docs/multiple.html Mon Oct 03 23:05:27 2005 +0000 @@ -1,12 +1,9 @@ - - + - Creating Applications: Adding Multiple-Choice Fields and Values - - - + + Creating Applications: Adding Multiple-Choice Fields and Values +

Creating Applications: Adding Multiple-Choice Fields and Values

Up to this point, we have only considered two kinds of Web form @@ -22,33 +19,18 @@ or many values presented in a list or menu, we shall first consider the case where only a single value can be chosen from such a selection.

-

Some item: 

+

Some item: 

Item type: - +

Itself containing more items:

-

Sub-item:

+

Sub-item:

From the item type list only one value may 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:new-attribute('value')}">
<option template:element="type-enum" template:expr="@value = ../@value" 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>
+
<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-field="value" name="..." type="text" value="..." />
<input name="..." template:selector-field="remove" type="submit" value="Remove" />
</p>
<p>
Item type:
<select template:multiple-choice-field="type,value" name="...">
<option template:multiple-choice-value="type-enum,value,selected" value="..." />
</select>
</p>
<p>
Itself containing more items:
</p>
<p template:element="subitem">
Sub-item: <input template:attribute-field="subvalue" name="..." type="text" value="..." />
<input name="..." template:selector-field="remove2" type="submit" value="Remove" />
</p>
<p>
<input name="..." template:selector-field="add2,subitem" type="submit" value="Add subitem" />
</p>
</div>
<p>
<input name="..." template:selector-field="add,item" type="submit" value="Add item" />
</p>

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

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

There are a lot of details here that need to be explained. Here is what was done:

    @@ -57,15 +39,11 @@
  1. Inside the paragraph, next to the label text, an HTML select element was added.
  2. The select element is mapped onto the type -element in the form data structure. However, HTML fields must produce -values and it makes no sense to interpret a textual value as an -element. Therefore, we indicate in the name of the select -element that the value submitted maps onto the value -attribute of the type element in the form data -structure.
  3. +element in the form data structure, indicating using a special template:multiple-choice-field attribute that the value attribute of the type +element will contain any chosen value from the list of values displayed in the page.
  4. Inside the select element, we include an option element which defines the values which will be presented to users -of the form. Note that the option element maps onto +of the form. Here, the special template:multiple-choice-value attribute indicates that the option element maps onto a type-enum element which is not mentioned in our revised form data structure above; this will be discussed below.
@@ -83,28 +61,17 @@ using a number of special annotations which make more sense when considering the above output structure:

+attribute. +
  • The template:multiple-choice-value annotation provides a final piece of information: the name of an attribute which will be created on the option element if the element's value matches the enclosing select element's value. This has the effect of making sure that the select element always reveals the selected value in its list of values. +
  • The value attribute is set to a value which does not matter - it will be replaced in the final output.
  • The result of this is that the type element in the this example structure fragment...

    <type value="2">
    <type-enum value="1"/>
    <type-enum value="2"/>
    <type-enum value="3"/>
    </type>
    @@ -118,70 +85,41 @@ will need to find a way of merging the range of allowed values into the user-edited form data before presenting that data using our template.

    -

    Merging Values into the Form Data

    +

    Document Initialisation

    There are many possible ways of inserting extra XML elements into an -existing XML document, but we shall concentrate on using an XSL -stylesheet to perform this merge operation. First, let us define a +existing XML document, but XSLForms provides an easy way of defining +lists of values that will be included in the way we desire. First, let +us define a document containing all the possible values for the type field:

    -
    <?xml version="1.0"?>
    <types>
    <type-enum value="(Not selected)"/>
    <type-enum value="Important"/>
    <type-enum value="Not important"/>
    <type-enum value="Personal"/>
    </types>
    +
    <?xml version="1.0"?>
    <type>
    <type-enum value="(Not selected)"/>
    <type-enum value="Important"/>
    <type-enum value="Not important"/>
    <type-enum value="Personal"/>
    </type>

    We shall refer to this document when inserting the different type-enum elements into our input form data structure to produce the output -structure described above. The stylesheet which performs this task is -quite scary for those not familiar with XSL, but it works 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. -
    3. 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. -
      3. Make a type element inside the item -element and process it.
      4. -
      -
    4. -
    5. When processing a new type element, do the -following:
      -
        -
      1. Copy the attributes of any existing type -element so that -the value attribute is retained.
      2. -
      3. Add the type-enum elements from the -document defined above.
      4. -
      -
    6. -
    -

    The stylesheet source code can be found in examples/Common/VerySimple/Resources/structure_types.xsl, -whereas the document defined above which contains the values can be +structure described above; it can be found in examples/Common/VerySimple/Resources/structure_types.xml.

    -

    Performing the Merge

    -

    To take advantage of these new documents, it is necessary to -introduce some code into the Web resource to perform the merge -operation. The special WebStack resource that we subclassed earlier provides some -convenient mechanisms for introducing XSL-based transformations, and we +

    Amending the Resource

    +

    To take advantage of this new information, it is necessary to +introduce some code into the Web resource to perform the document initialisation. The special WebStack resource that we subclassed earlier provides some +convenient mechanisms for introducing XML documents and initialisations, and we shall add a few extra attributes to our resource class in order to take advantage of them:

    -
        # Under template_resources...

    transform_resources = {
    "types" : ["structure_types.xsl"]
    }
    document_resources = {
    "types" : "structure_types.xml"
    }
    +
        # Under template_resources...

    init_resources = {
    "structure" : ("structure_template.xhtml", "structure_input.xsl")
    }
    document_resources = {
    "types" : "structure_types.xml"
    }

    These attributes define the following things:

      -
    1. A transformation called types which uses -the structure_types.xsl stylesheet file.
    2. +
    3. A initialisation called structure which links +the structure_template.xhtml file (the template) to the structure_input.xsl stylesheet file. This is very similar to the way the template_resources dictionary links templates to other stylesheet files producing output.
    4. A document referred to by the name types which is provided by the structure_types.xml file.
    -

    To actually perform the merge operation, we need to add a few extra +

    To actually perform the initalisation or merge operation, we need to add a few extra lines of code after the addition and deletion operations in the respond_to_form method:

    -
            # Under the addition and deletion operations...

    # Transform, adding enumerations/ranges.

    types_xsl_list = self.prepare_transform("types")
    types_xml = self.prepare_document("types")
    structure = self.get_result(types_xsl_list, structure, references={"types" : types_xml})

    # Start the response.
    +
            # Under the addition and deletion operations...

    # Initialise the document, adding enumerations/ranges.

    structure_xsl = self.prepare_initialiser("structure")
    types_xml = self.prepare_document("types")
    structure = self.get_result([structure_xsl], structure, references={"type" : types_xml})

    # Start the response.

    These lines do the following things:

      -
    1. Obtain the stylesheets for the types -transformation.
    2. +
    3. Obtain the stylesheet for the structure initialisation.
    4. Obtain the types document containing the values to be merged into the form data.
    5. -
    6. Take the stylesheets and apply them to the form data, structure, +
    7. Take the stylesheet and apply it to the form data, structure, using a reference to the types document containing the values.
    @@ -190,9 +128,7 @@ element in that document.

    Other Multiple-Choice Data

    We have now added a simple, single-valued multiple-choice field to -the application. However, many applications often need to obtain multivalued multiple-choice data, and this +the application. However, many applications often need to obtain multivalued multiple-choice data, and this kind of information is investigated in the next part of the development process.

    - - + \ No newline at end of file diff -r 6e64e6d7aea0 -r 2fa5fb4ba21a docs/multivalue.html --- a/docs/multivalue.html Mon Oct 03 23:04:48 2005 +0000 +++ b/docs/multivalue.html Mon Oct 03 23:05:27 2005 +0000 @@ -1,12 +1,10 @@ - - + - Creating Applications: Adding Multivalued Fields - - - + + Creating Applications: Adding Multivalued Fields + +

    Creating Applications: Adding Multivalued Fields

    Although some applications only require multiple-choice fields where @@ -26,49 +24,32 @@ users to select one or many values presented in a list or menu.

    -

    Some item: 

    +

    Some item: 

    Item type: - +

    Itself containing more items:

    -

    Sub-item:

    +

    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>
    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>
    +
    <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-field="value" name="..." type="text" value="..." />
    <input name="..." template:selector-field="remove" type="submit" value="Remove" />
    </p>
    <p>
    Item type:
    <select name="..." template:multiple-choice-list-field="type,type-enum,value" multiple="multiple">
    <option template:multiple-choice-list-value="type-enum,value,selected" value="..." />
    </select>
    </p>
    <p>
    Itself containing more items:
    </p>
    <p template:element="subitem">
    Sub-item: <input template:attribute-field="subvalue" name="..." type="text" value="..." />
    <input name="..." template:selector-field="remove2" type="submit" value="Remove" />
    </p>
    <p>
    <input name="..." template:selector-field="add2,subitem" type="submit" value="Add subitem" />
    </p>
    </div>
    <p>
    <input name="..." template:selector-field="add,item" 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 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.
    2. +element in the form data structure. However, we use a different attribute, template:multiple-choice-list-field, to indicate that a type +element is created when the form data is submitted, but instead of a single value being added to the value attribute of that one element, a separate type-enum +element is created within the type +element with a value in its value attribute for each value submitted. This means that many type-enum +elements may be created within the type +element, and each one of them will have a different value attribute.
    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.
    5. +element now employs the template:multiple-choice-list-value annotation.

    Output Structures

    Unlike in the single-valued case, the revised the form data @@ -89,73 +70,17 @@

    <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?

    +

    Above, the special value-is-set +attribute is an XSLForms mechanism to remember which values were set. +Fortunately, the document initialisation mechanism automatically +distinguishes between different multiple-choice field types and +understands where the above approach needs to be employed.

    -Here, we have to do two things: to include the full range of possible -values so that the user may select from that range, and yet we must -remember which values were previously selected. If we just merged -the 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. -

    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 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>
    <type-enum value="1"/>
    <type-enum value="2" value-is-set="true"/>
    <type-enum value="3" value-is-set="true"/>
    </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: -
      -
    1. Descend into the form data structure, copying all elements, -attributes and text that the stylesheet is not programmed to recognise.
    2. -
    3. 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. -
      3. Produce a new type element and process it.
      4. -
      -
    4. -
    5. When processing a new type element, do the -following:
      -
        -
      1. Inside this new 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.
      2. -
      -
    6. -
    7. 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-enum elements, set the -special value-is-set attribute on that type-enum -element.
    8. -
    -

    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

    +

    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"]
    }
    +
        template_resources = {
    "structure" : ("structure_multivalue_template.xhtml", "structure_output.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 @@ -165,5 +90,4 @@

    Now that we have designed and implemented a simple application, it may be worth reading some recommendations about developing your own applications.

    - - + \ No newline at end of file diff -r 6e64e6d7aea0 -r 2fa5fb4ba21a docs/selectors.html --- a/docs/selectors.html Mon Oct 03 23:04:48 2005 +0000 +++ b/docs/selectors.html Mon Oct 03 23:05:27 2005 +0000 @@ -1,12 +1,9 @@ - - + - Creating Applications: Add Selectors - - - + + Creating Applications: Add Selectors +

    Creating Applications: Add Selectors

    In the previous activity we annotated the template @@ -29,23 +26,19 @@

    Taking the example HTML code from before, we add some of these selector annotations 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>
    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>
    +
    <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-field="value" name="..." type="text" value="..." />
    <input name="..." template:selector-field="remove" type="submit" value="Remove" />
    </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="..." template:selector-field="remove2" type="submit" value="Remove" />
    </p>
    <p>
    <input name="..." template:selector-field="add2,subitem" type="submit" value="Add subitem" />
    </p>
    </div>
    <p>
    <input name="..." template:selector-field="add,item" type="submit" value="Add item" />
    </p>

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

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

    The Remove Buttons

    Some of the attributes in the previous HTML code have been changed:

    What these amendments provide is a means for the XSLForms framework @@ -69,12 +62,13 @@ code:

    @@ -100,11 +94,8 @@

    We define the names of the selectors in the above cases to be add2 and add respectively, since the special values begin with -these identifiers.

    +these identifiers. Moreover, we mention that the selectors are intended to add subitem and item elements respectively - this has certain implications for the behaviour of the application that will be considered later.

    We should now have a template that is sufficiently complete to be -used in a real application, and the writing of the application code itself will be -investigated in the next activity in the development process.

    - - +used in a real application, and the writing of the application code itself will be +investigated in the next activity in the development process.

    + \ No newline at end of file diff -r 6e64e6d7aea0 -r 2fa5fb4ba21a docs/structure.html --- a/docs/structure.html Mon Oct 03 23:04:48 2005 +0000 +++ b/docs/structure.html Mon Oct 03 23:05:27 2005 +0000 @@ -1,12 +1,10 @@ - - + - Creating Applications: Add Structure - - - + + Creating Applications: Add Structure + +

    Creating Applications: Add Structure

    Earlier, we defined the structure of the form @@ -19,15 +17,7 @@ adding special attributes to the HTML code.

    Consider the interesting parts of the template side by side with the structure information:

    -
    <structure>                                   <body>

    <item <div>
    <p>
    value="some value"> Some item: <input name="value" type="text" value="some value" />
    <input name="remove" type="submit" value="Remove" />
    </p>
    <p>
    Itself containing more items:
    </p>
    <subitem <p>
     subvalue="some other value"/> Sub-item: <input name="subvalue" type="text" value="some other value" />
    <input name="remove2" type="submit" value="Remove" />
    </p>
    <p>
    <input name="add2" type="submit" value="Add subitem" />
    </p>
    </item> </div>
    <p>
    <input name="add" type="submit" value="Add item" />
    </p>

    </structure> </body>
    +
    <structure>                                   <body>

    <item <div>
    <p>
    value="some value"> Some item: <input name="value" type="text" value="some value" />
    <input name="remove" type="submit" value="Remove" />
    </p>
    <p>
    Itself containing more items:
    </p>
    <subitem <p>
     subvalue="some other value"/> Sub-item: <input name="subvalue" type="text" value="some other value" />
    <input name="remove2" type="submit" value="Remove" />
    </p>
    <p>
    <input name="add2" type="submit" value="Add subitem" />
    </p>
    </item> </div>
    <p>
    <input name="add" type="submit" value="Add item" />
    </p>

    </structure> </body>

    To make such connections, we will annotate the HTML code using special attributes and values.