# HG changeset patch # User Paul Boddie # Date 1226883018 -3600 # Node ID 7bcd6ba5baacd5f00f5601b8429e5e8e3d0a9ae8 # Parent cb3f3f87d086b2fe7d7afb902671336b5c24660f Fixed multipart form data handling, permitting file uploads in non-structural parameters. Added template:output and template:select annotations. Added some documentation for template:select. Improved the questionnaire example, adding import of exported questionnaires, question moving, and providing a more flexible selection of response types. diff -r cb3f3f87d086 -r 7bcd6ba5baac README.txt --- a/README.txt Sun Nov 16 01:19:33 2008 +0100 +++ b/README.txt Mon Nov 17 01:50:18 2008 +0100 @@ -75,6 +75,14 @@ * Removed default encoding and path_encoding attributes from the XSLFormsResource class, since the default response encoding should be used instead or set using WebStack's EncodingSelector. + * Added a template:output annotation for the production of output content + where the annotations should not be considered for inclusion in a schema, + typically because the annotated content duplicates content elsewhere in a + template. + * Added a template:select annotation for the presentation of arbitrary + sections of a document within a template. + * Fixed handling of multipart form data, permitting file uploads for input + parameters which are outside the form document structure. New in XSLTools 0.5 (Changes since XSLTools 0.4.6) -------------------------------------------------- diff -r cb3f3f87d086 -r 7bcd6ba5baac XSLForms/Fields.py --- a/XSLForms/Fields.py Sun Nov 16 01:19:33 2008 +0100 +++ b/XSLForms/Fields.py Mon Nov 17 01:50:18 2008 +0100 @@ -124,9 +124,10 @@ if type(value) == type(""): value = unicode(value, encoding=self.encoding) - # Remove CR characters. + # Remove CR characters, ignoring non-textual parameters. - node.setAttributeNS(EMPTY_NAMESPACE, t[0], value.replace("\r", "")) + if isinstance(value, (str, unicode)): + node.setAttributeNS(EMPTY_NAMESPACE, t[0], value.replace("\r", "")) break elif len(t) == 2: @@ -161,9 +162,10 @@ if type(subvalue) == type(""): subvalue = unicode(subvalue, encoding=self.encoding) - # Remove CR characters. + # Remove CR characters, ignoring non-textual parameters. - subnode.setAttributeNS(EMPTY_NAMESPACE, t[2], subvalue.replace("\r", "")) + if isinstance(value, (str, unicode)): + subnode.setAttributeNS(EMPTY_NAMESPACE, t[2], subvalue.replace("\r", "")) def complete_selectors(self, selectors, fields, documents, create): diff -r cb3f3f87d086 -r 7bcd6ba5baac XSLForms/Resources/WebResources.py --- a/XSLForms/Resources/WebResources.py Sun Nov 16 01:19:33 2008 +0100 +++ b/XSLForms/Resources/WebResources.py Mon Nov 17 01:50:18 2008 +0100 @@ -122,7 +122,7 @@ for name, values in parameters.items(): new_values = [] for value in values: - if value.endswith("\x00"): + if isinstance(value, (str, unicode)) and value.endswith("\x00"): new_values.append(value[:-1]) else: new_values.append(value) @@ -302,7 +302,8 @@ parameters = trans.get_fields_from_path() form.set_parameters(parameters) - elif method == "POST" and content_type.media_type == "application/x-www-form-urlencoded": + elif method == "POST" and content_type.media_type in ( + "application/x-www-form-urlencoded", "multipart/form-data"): # Get the fields from the request body. diff -r cb3f3f87d086 -r 7bcd6ba5baac XSLForms/XSL/Prepare.xsl --- a/XSLForms/XSL/Prepare.xsl Sun Nov 16 01:19:33 2008 +0100 +++ b/XSLForms/XSL/Prepare.xsl Mon Nov 17 01:50:18 2008 +0100 @@ -4,7 +4,7 @@ stylesheet - something which is capable of transforming XML documents into Web pages or other kinds of XML documents. -Copyright (C) 2005, 2007 Paul Boddie +Copyright (C) 2005, 2006, 2007, 2008 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free @@ -147,6 +147,17 @@ + + + + + + + + + + + @@ -324,7 +335,7 @@ - + diff -r cb3f3f87d086 -r 7bcd6ba5baac XSLForms/XSL/Schema.xsl --- a/XSLForms/XSL/Schema.xsl Sun Nov 16 01:19:33 2008 +0100 +++ b/XSLForms/XSL/Schema.xsl Mon Nov 17 01:50:18 2008 +0100 @@ -1,6 +1,6 @@ + diff -r cb3f3f87d086 -r 7bcd6ba5baac docs/reference.html --- a/docs/reference.html Sun Nov 16 01:19:33 2008 +0100 +++ b/docs/reference.html Mon Nov 17 01:50:18 2008 +0100 @@ -144,6 +144,34 @@

See the "Internationalisation" document for more information on this attribute.

+

template:select

+ +

This attribute is used to select sections of the XML document being presented +which are potentially different from the current element implied by the +structure communicated in the template. +

+ +

Example:

+ +
+<select template:attribute-field="destination">
+  <option template:select="../question" template:value="position()" value="{position()}"></option>
+</select>
+
+ +

In this example, the option element is replicated for each +question element appearing below the parent element in the XML +document being presented. Since a list of results is traversed as a result, the +position of each question element can be obtained and used in the +resulting output. +

+ +

Syntax:

+ +
XPath-expression
+ +

The specified expression is evaluated in the context of the current element.

+

Initialisation Annotations

The annotation attributes in this section control the initialisation of documents where this is done by the XSLForms toolkit.

diff -r cb3f3f87d086 -r 7bcd6ba5baac examples/Common/Questionnaire/Resources/question_response_types.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/Common/Questionnaire/Resources/question_response_types.xml Mon Nov 17 01:50:18 2008 +0100 @@ -0,0 +1,6 @@ + + + Choice + Text + Choice with text + diff -r cb3f3f87d086 -r 7bcd6ba5baac examples/Common/Questionnaire/Resources/question_template.xhtml --- a/examples/Common/Questionnaire/Resources/question_template.xhtml Sun Nov 16 01:19:33 2008 +0100 +++ b/examples/Common/Questionnaire/Resources/question_template.xhtml Mon Nov 17 01:50:18 2008 +0100 @@ -12,16 +12,30 @@

Questionnaire Editor

-

Enter questions and possible responses below.

+
- +

+Either import a previously generated XML file: + + +

+

Or enter questions and possible responses below.

+ - + - + - - - - - @@ -50,8 +54,12 @@ - - + + - - - - -
Question + Question #n
+ + + + +
@@ -33,16 +47,6 @@
Response - No text answer
- Text before
-
Allow multiple choices...
+ + @@ -60,64 +68,73 @@
- Text after -
+
+ + + +
+ +

The preview of your questionnaire is shown here:

+ +
+ + + + + + + + + + + + +
Question #n + Question +
Response +
+

+ + Choice +

+

+ +

+
+
+ +
+ +
+ +
+

to make the questionnaire longer.

+ to refresh the preview. +

+ +

+ to produce an XML file + containing the questions and responses. +

+ +

when all the questions and responses are ready.

- - -
- - - - - - - - - - - - -
Question - Question -
Response -

- -

-

- - Choice -

-

- -

-
- -
-
diff -r cb3f3f87d086 -r 7bcd6ba5baac examples/Common/Questionnaire/Resources/styles/styles.css --- a/examples/Common/Questionnaire/Resources/styles/styles.css Sun Nov 16 01:19:33 2008 +0100 +++ b/examples/Common/Questionnaire/Resources/styles/styles.css Mon Nov 17 01:50:18 2008 +0100 @@ -1,3 +1,5 @@ +/* Page sections. */ + div.questionnaire { width: 40%; float: left; @@ -6,10 +8,20 @@ div.preview { width: 50%; float: right; +} + +div.operations { + padding-top: 10px; + clear: both; +} + +/* Preview and shadow effect. */ + +div.shadow { background-color: #555555; } -div.preview table.preview { +div.shadow table.preview { background-color: #ffffff; border: 1px solid #000000; padding: 5px; @@ -18,10 +30,19 @@ left: -10px; } +/* Questionnaire and preview tables. */ + table.preview { + width: 100%; border-spacing: 0px; } +table.questionnaire { + width: 100%; +} + +/* Questionnaire and preview cells. */ + table.questionnaire td, table.questionnaire th { padding: 5px; margin: 0px; @@ -32,29 +53,28 @@ margin: 0px; } -table.preview td p.text-before { - margin-top: 0px; -} - -table.preview td p.choice { - padding: 2px; - margin: 0px 0px 0px 0px; +table.preview td p { + margin: 0px 5px 5px 5px; } .question, .question-options { + background-color: #dddddd; + color: #000000; + vertical-align: top; +} + +.question .control { + font-weight: normal; +} + +.response, .response-options { background-color: #ffffff; color: #000000; vertical-align: top; } -.response, .response-options { +.choice, .choice-options { background-color: #eeeeee; color: #000000; vertical-align: top; } - -.choice, .choice-options { - background-color: #dddddd; - color: #000000; - vertical-align: top; -} diff -r cb3f3f87d086 -r 7bcd6ba5baac examples/Common/Questionnaire/__init__.py --- a/examples/Common/Questionnaire/__init__.py Sun Nov 16 01:19:33 2008 +0100 +++ b/examples/Common/Questionnaire/__init__.py Mon Nov 17 01:50:18 2008 +0100 @@ -4,8 +4,10 @@ import WebStack.Generic from XSLForms.Resources.WebResources import \ - XSLFormsResource, output, resources, prepare_resources as xslforms_prepare_resources + XSLFormsResource, input, output, resources, prepare_resources as xslforms_prepare_resources import os +import libxml2dom +import xml.dom # Site map imports. @@ -27,6 +29,12 @@ template_resources = { "questionnaire" : output("question_template.xhtml") } + init_resources = { + "questionnaire" : input("question_template.xhtml") + } + document_resources = { + "response-types" : "question_response_types.xml" + } def select_activity(self, trans, form): form.set_activity("questionnaire") @@ -41,6 +49,25 @@ self.add_elements(selectors.get("add-choice"), "choice") self.remove_elements(selectors.get("remove-choice")) + # Move questions. + # NOTE: Potentially a DOM convenience method here. + + for question in selectors.get("move-question", []): + destination = int(question.getAttribute("destination")) + if destination > 1: + destination += 1 + root = questionnaire.documentElement + target = (root.xpath("question[position() = %d]" % destination) or [None])[0] + root.removeChild(question) + if target is not None: + try: + root.insertBefore(question, target) + except xml.dom.NotFoundErr: + target = (root.xpath("question[position() = %d]" % destination) or [None])[0] + root.insertBefore(question, target) + else: + root.appendChild(question) + # Add questions using the normal request parameter. if parameters.has_key("add-question"): @@ -55,6 +82,23 @@ questionnaire.toStream(trans.get_response_stream(), trans.get_response_stream_encoding()) raise WebStack.Generic.EndOfResponse + # Support uploading of files. + + if parameters.has_key("import"): + importfile = parameters["importfile"][0] + try: + doc = libxml2dom.parse(importfile.stream) + form.set_document(doc) + except libxml2dom.LSException: + pass + + def init_document(self, trans, form): + + # Transform, adding enumerations/ranges. + + response_types_xml = self.prepare_document("response-types") + XSLFormsResource.init_document(self, trans, form, references={"response-type" : response_types_xml}) + # Site map initialisation. def get_site():