1.1 --- a/README.txt Sun Nov 16 01:19:33 2008 +0100
1.2 +++ b/README.txt Mon Nov 17 01:50:18 2008 +0100
1.3 @@ -75,6 +75,14 @@
1.4 * Removed default encoding and path_encoding attributes from the
1.5 XSLFormsResource class, since the default response encoding should be used
1.6 instead or set using WebStack's EncodingSelector.
1.7 + * Added a template:output annotation for the production of output content
1.8 + where the annotations should not be considered for inclusion in a schema,
1.9 + typically because the annotated content duplicates content elsewhere in a
1.10 + template.
1.11 + * Added a template:select annotation for the presentation of arbitrary
1.12 + sections of a document within a template.
1.13 + * Fixed handling of multipart form data, permitting file uploads for input
1.14 + parameters which are outside the form document structure.
1.15
1.16 New in XSLTools 0.5 (Changes since XSLTools 0.4.6)
1.17 --------------------------------------------------
2.1 --- a/XSLForms/Fields.py Sun Nov 16 01:19:33 2008 +0100
2.2 +++ b/XSLForms/Fields.py Mon Nov 17 01:50:18 2008 +0100
2.3 @@ -124,9 +124,10 @@
2.4 if type(value) == type(""):
2.5 value = unicode(value, encoding=self.encoding)
2.6
2.7 - # Remove CR characters.
2.8 + # Remove CR characters, ignoring non-textual parameters.
2.9
2.10 - node.setAttributeNS(EMPTY_NAMESPACE, t[0], value.replace("\r", ""))
2.11 + if isinstance(value, (str, unicode)):
2.12 + node.setAttributeNS(EMPTY_NAMESPACE, t[0], value.replace("\r", ""))
2.13 break
2.14
2.15 elif len(t) == 2:
2.16 @@ -161,9 +162,10 @@
2.17 if type(subvalue) == type(""):
2.18 subvalue = unicode(subvalue, encoding=self.encoding)
2.19
2.20 - # Remove CR characters.
2.21 + # Remove CR characters, ignoring non-textual parameters.
2.22
2.23 - subnode.setAttributeNS(EMPTY_NAMESPACE, t[2], subvalue.replace("\r", ""))
2.24 + if isinstance(value, (str, unicode)):
2.25 + subnode.setAttributeNS(EMPTY_NAMESPACE, t[2], subvalue.replace("\r", ""))
2.26
2.27 def complete_selectors(self, selectors, fields, documents, create):
2.28
3.1 --- a/XSLForms/Resources/WebResources.py Sun Nov 16 01:19:33 2008 +0100
3.2 +++ b/XSLForms/Resources/WebResources.py Mon Nov 17 01:50:18 2008 +0100
3.3 @@ -122,7 +122,7 @@
3.4 for name, values in parameters.items():
3.5 new_values = []
3.6 for value in values:
3.7 - if value.endswith("\x00"):
3.8 + if isinstance(value, (str, unicode)) and value.endswith("\x00"):
3.9 new_values.append(value[:-1])
3.10 else:
3.11 new_values.append(value)
3.12 @@ -302,7 +302,8 @@
3.13 parameters = trans.get_fields_from_path()
3.14 form.set_parameters(parameters)
3.15
3.16 - elif method == "POST" and content_type.media_type == "application/x-www-form-urlencoded":
3.17 + elif method == "POST" and content_type.media_type in (
3.18 + "application/x-www-form-urlencoded", "multipart/form-data"):
3.19
3.20 # Get the fields from the request body.
3.21
4.1 --- a/XSLForms/XSL/Prepare.xsl Sun Nov 16 01:19:33 2008 +0100
4.2 +++ b/XSLForms/XSL/Prepare.xsl Mon Nov 17 01:50:18 2008 +0100
4.3 @@ -4,7 +4,7 @@
4.4 stylesheet - something which is capable of transforming XML documents into Web
4.5 pages or other kinds of XML documents.
4.6
4.7 -Copyright (C) 2005, 2007 Paul Boddie <paul@boddie.org.uk>
4.8 +Copyright (C) 2005, 2006, 2007, 2008 Paul Boddie <paul@boddie.org.uk>
4.9
4.10 This program is free software; you can redistribute it and/or modify it under
4.11 the terms of the GNU Lesser General Public License as published by the Free
4.12 @@ -147,6 +147,17 @@
4.13
4.14
4.15
4.16 + <!-- Match elements referencing selected sections. -->
4.17 +
4.18 + <xsl:template match="*[@template:select]" priority="1">
4.19 + <!-- Produce a loop using the annotation's content. -->
4.20 + <axsl:for-each select="{@template:select}">
4.21 + <xsl:call-template name="enter-attribute"/>
4.22 + </axsl:for-each>
4.23 + </xsl:template>
4.24 +
4.25 +
4.26 +
4.27 <!-- Match special conditional expression attributes. -->
4.28
4.29 <xsl:template match="*[@template:if]" priority="2">
4.30 @@ -324,7 +335,7 @@
4.31
4.32 <!-- Remove template attributes. -->
4.33
4.34 - <xsl:template match="@template:element|@template:init|@template:attribute|@template:value|@template:expr|@template:expr-attr|@template:effect|@template:if|@template:i18n|@template:copy">
4.35 + <xsl:template match="@template:element|@template:init|@template:attribute|@template:value|@template:expr|@template:expr-attr|@template:effect|@template:if|@template:i18n|@template:copy|@template:select|@template:output">
4.36 </xsl:template>
4.37
4.38
5.1 --- a/XSLForms/XSL/Schema.xsl Sun Nov 16 01:19:33 2008 +0100
5.2 +++ b/XSLForms/XSL/Schema.xsl Mon Nov 17 01:50:18 2008 +0100
5.3 @@ -1,6 +1,6 @@
5.4 <?xml version="1.0"?>
5.5 <!--
5.6 -Copyright (C) 2005 Paul Boddie <paul@boddie.org.uk>
5.7 +Copyright (C) 2005, 2006, 2007, 2008 Paul Boddie <paul@boddie.org.uk>
5.8
5.9 This program is free software; you can redistribute it and/or modify it under
5.10 the terms of the GNU Lesser General Public License as published by the Free
5.11 @@ -51,6 +51,9 @@
5.12 <xsl:variable name="first-init" select="substring-before($other-init, ',')"/>
5.13 <xsl:variable name="remaining-init" select="substring-after($other-init, ',')"/>
5.14 <xsl:choose>
5.15 + <xsl:when test="@template:output">
5.16 + <!-- Output elements are omitted from the schema and are only used to produce output. -->
5.17 + </xsl:when>
5.18 <xsl:when test="$first-element = ''">
5.19 <xsl:call-template name="next-element">
5.20 <xsl:with-param name="first-element" select="$other-elements"/>
6.1 --- a/docs/reference.html Sun Nov 16 01:19:33 2008 +0100
6.2 +++ b/docs/reference.html Mon Nov 17 01:50:18 2008 +0100
6.3 @@ -144,6 +144,34 @@
6.4
6.5 <p>See the <a href="internationalisation.html">"Internationalisation"</a> document for more information on this attribute.</p>
6.6
6.7 +<h3><a name="i18n"></a>template:select</h3>
6.8 +
6.9 +<p>This attribute is used to select sections of the XML document being presented
6.10 +which are potentially different from the current element implied by the
6.11 +structure communicated in the template.
6.12 +</p>
6.13 +
6.14 +<p>Example:</p>
6.15 +
6.16 +<pre>
6.17 +<select template:attribute-field="destination">
6.18 + <option template:select="../question" template:value="position()" value="{position()}"></option>
6.19 +</select>
6.20 +</pre>
6.21 +
6.22 +<p>In this example, the <code>option</code> element is replicated for each
6.23 +<code>question</code> element appearing below the parent element in the XML
6.24 +document being presented. Since a list of results is traversed as a result, the
6.25 +position of each <code>question</code> element can be obtained and used in the
6.26 +resulting output.
6.27 +</p>
6.28 +
6.29 +<p>Syntax:</p>
6.30 +
6.31 +<pre>XPath-expression</pre>
6.32 +
6.33 +<p>The specified expression is evaluated in the context of the current element.</p>
6.34 +
6.35 <h2>Initialisation Annotations</h2>
6.36
6.37 <p>The annotation attributes in this section control the initialisation of documents where this is done by the XSLForms toolkit.</p>
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/examples/Common/Questionnaire/Resources/question_response_types.xml Mon Nov 17 01:50:18 2008 +0100
7.3 @@ -0,0 +1,6 @@
7.4 +<?xml version="1.0"?>
7.5 +<response-type>
7.6 + <response-type-enum value="choice">Choice</response-type-enum>
7.7 + <response-type-enum value="text">Text</response-type-enum>
7.8 + <response-type-enum value="textual-choice">Choice with text</response-type-enum>
7.9 +</response-type>
8.1 --- a/examples/Common/Questionnaire/Resources/question_template.xhtml Sun Nov 16 01:19:33 2008 +0100
8.2 +++ b/examples/Common/Questionnaire/Resources/question_template.xhtml Mon Nov 17 01:50:18 2008 +0100
8.3 @@ -12,16 +12,30 @@
8.4 <body template:element="questionnaire">
8.5 <h1>Questionnaire Editor</h1>
8.6
8.7 -<p>Enter questions and possible responses below.</p>
8.8 +<form method="POST" action="" enctype="multipart/form-data">
8.9
8.10 -<form method="POST" action="">
8.11 +<p>
8.12 +Either import a previously generated XML file:
8.13 +<input type="file" name="importfile" />
8.14 +<input type="submit" value="Import" name="import" />
8.15 +</p>
8.16
8.17 <div class="questionnaire">
8.18
8.19 + <p>Or enter questions and possible responses below.</p>
8.20 +
8.21 <table class="questionnaire">
8.22 - <tbody template:element="question">
8.23 + <tbody template:element="question" template:init="no">
8.24 <tr>
8.25 - <th class="question">Question</th>
8.26 + <th class="question">
8.27 + Question #<span template:value="count(preceding-sibling::question) + 1">n</span><br/>
8.28 + <span class="control">
8.29 + <input type="submit" value="Move to..." name="..." template:selector-field="move-question" />
8.30 + <select template:attribute-field="destination">
8.31 + <option template:select="../question" template:value="position()" value="{position()}"></option>
8.32 + </select>
8.33 + </span>
8.34 + </th>
8.35 <td class="question">
8.36 <textarea cols="40" rows="4" template:attribute-area="question-text,insert"
8.37 name="...">Question</textarea>
8.38 @@ -33,16 +47,6 @@
8.39 <tr>
8.40 <th class="response">Response</th>
8.41 <td class="response">
8.42 - <input type="radio" template:attribute-button="text-response,none,checked"
8.43 - name="..." value="..." /> No text answer<br />
8.44 - <input type="radio" template:attribute-button="text-response,before,checked"
8.45 - name="..." value="..." /> Text before<br />
8.46 - </td>
8.47 - <td></td>
8.48 - </tr>
8.49 - <tr>
8.50 - <td class="response"></td>
8.51 - <td class="response">
8.52 <input type="checkbox" template:attribute-button="choice-response,multiple,checked"
8.53 name="..." value="choice" /> Allow multiple choices...
8.54 </td>
8.55 @@ -50,8 +54,12 @@
8.56 <input type="submit" value="Add choice" name="..." template:selector-field="add-choice,choice" />
8.57 </td>
8.58 </tr>
8.59 - <tr template:element="choice">
8.60 - <td class="response"></td>
8.61 + <tr template:element="choice" template:init="no">
8.62 + <td class="choice">
8.63 + <select template:multiple-choice-field="response-type,value" name="...">
8.64 + <option template:multiple-choice-value="response-type-enum,value,selected,text()"></option>
8.65 + </select>
8.66 + </td>
8.67 <td class="choice">
8.68 <input type="text" size="40" template:attribute-field="response-choice"
8.69 name="..." value="..." />
8.70 @@ -60,64 +68,73 @@
8.71 <input type="submit" value="Remove choice" name="..." template:selector-field="remove-choice" />
8.72 </td>
8.73 </tr>
8.74 - <tr>
8.75 - <td class="response"></td>
8.76 - <td class="response">
8.77 - <input type="radio" template:attribute-button="text-response,after,checked"
8.78 - name="..." value="..." /> Text after
8.79 - </td>
8.80 - <td></td>
8.81 - </tr>
8.82 </tbody>
8.83 </table>
8.84
8.85 +</div>
8.86 +
8.87 +<!-- Repeat the questionnaire in preview mode. -->
8.88 +
8.89 +<div class="preview">
8.90 +
8.91 + <p>The preview of your questionnaire is shown here:</p>
8.92 +
8.93 + <div class="shadow">
8.94 +
8.95 + <table class="preview">
8.96 + <tbody template:element="question" template:output="true" template:init="no">
8.97 + <tr>
8.98 + <th class="question">Question #<span template:value="count(preceding-sibling::question) + 1">n</span></th>
8.99 + <td class="question">
8.100 + <span template:value="@question-text">Question</span>
8.101 + </td>
8.102 + </tr>
8.103 + <tr>
8.104 + <th class="response">Response</th>
8.105 + <td class="response">
8.106 + <div template:element="choice" template:init="no">
8.107 + <p template:if="@response-choice != '' or not(response-type/@value = 'text')" xml:space="preserve">
8.108 + <input template:if="not(response-type/@value = 'text')"
8.109 + type="{template:choice(../@choice-response = 'multiple', 'checkbox', 'radio')}"
8.110 + name="_unused" value="..." />
8.111 + <span template:value="@response-choice">Choice</span>
8.112 + </p>
8.113 + <p template:if="response-type/@value and not(response-type/@value = 'choice')">
8.114 + <input type="text" size="40" name="_unused" />
8.115 + </p>
8.116 + </div>
8.117 + </td>
8.118 + </tr>
8.119 + </tbody>
8.120 + </table>
8.121 +
8.122 + </div>
8.123 +
8.124 +</div>
8.125 +
8.126 +<div class="operations">
8.127 +
8.128 <p>
8.129 <input type="submit" value="Add question" name="add-question" /> to make
8.130 the questionnaire longer.
8.131 </p>
8.132
8.133 <p>
8.134 + <input type="submit" value="Update" name="update" /> to refresh the preview.
8.135 + </p>
8.136 +
8.137 + <p>
8.138 + <input type="submit" value="Export" name="export" /> to produce an XML file
8.139 + containing the questions and responses.
8.140 + </p>
8.141 +
8.142 + <p>
8.143 <input type="submit" value="Finish" name="finish" /> when all the questions
8.144 and responses are ready.
8.145 </p>
8.146
8.147 </div>
8.148
8.149 -<!-- Repeat the questionnaire in preview mode. -->
8.150 -
8.151 -<div class="preview">
8.152 -
8.153 - <table class="preview">
8.154 - <tbody template:element="question">
8.155 - <tr>
8.156 - <th class="question">Question</th>
8.157 - <td class="question">
8.158 - <span template:value="@question-text">Question</span>
8.159 - </td>
8.160 - </tr>
8.161 - <tr>
8.162 - <th class="response">Response</th>
8.163 - <td class="response">
8.164 - <p template:if="@text-response = 'before'" class="text-before">
8.165 - <input type="text" size="40" template:attribute-field="response-text"
8.166 - name="..." value="..." />
8.167 - </p>
8.168 - <p template:element="choice" class="choice" xml:space="preserve">
8.169 - <input type="{template:choice(../@choice-response = 'multiple', 'checkbox', 'radio')}"
8.170 - template:attribute-button="selected,true,checked" name="..." value="..." />
8.171 - <span template:value="@response-choice">Choice</span>
8.172 - </p>
8.173 - <p template:if="@text-response = 'after'" class="text-after">
8.174 - <input type="text" size="40" template:attribute-field="response-text"
8.175 - name="..." value="..." />
8.176 - </p>
8.177 - </td>
8.178 - </tr>
8.179 - </tbody>
8.180 - </table>
8.181 -
8.182 -</div>
8.183 -
8.184 </form>
8.185
8.186 </body>
9.1 --- a/examples/Common/Questionnaire/Resources/styles/styles.css Sun Nov 16 01:19:33 2008 +0100
9.2 +++ b/examples/Common/Questionnaire/Resources/styles/styles.css Mon Nov 17 01:50:18 2008 +0100
9.3 @@ -1,3 +1,5 @@
9.4 +/* Page sections. */
9.5 +
9.6 div.questionnaire {
9.7 width: 40%;
9.8 float: left;
9.9 @@ -6,10 +8,20 @@
9.10 div.preview {
9.11 width: 50%;
9.12 float: right;
9.13 +}
9.14 +
9.15 +div.operations {
9.16 + padding-top: 10px;
9.17 + clear: both;
9.18 +}
9.19 +
9.20 +/* Preview and shadow effect. */
9.21 +
9.22 +div.shadow {
9.23 background-color: #555555;
9.24 }
9.25
9.26 -div.preview table.preview {
9.27 +div.shadow table.preview {
9.28 background-color: #ffffff;
9.29 border: 1px solid #000000;
9.30 padding: 5px;
9.31 @@ -18,10 +30,19 @@
9.32 left: -10px;
9.33 }
9.34
9.35 +/* Questionnaire and preview tables. */
9.36 +
9.37 table.preview {
9.38 + width: 100%;
9.39 border-spacing: 0px;
9.40 }
9.41
9.42 +table.questionnaire {
9.43 + width: 100%;
9.44 +}
9.45 +
9.46 +/* Questionnaire and preview cells. */
9.47 +
9.48 table.questionnaire td, table.questionnaire th {
9.49 padding: 5px;
9.50 margin: 0px;
9.51 @@ -32,29 +53,28 @@
9.52 margin: 0px;
9.53 }
9.54
9.55 -table.preview td p.text-before {
9.56 - margin-top: 0px;
9.57 -}
9.58 -
9.59 -table.preview td p.choice {
9.60 - padding: 2px;
9.61 - margin: 0px 0px 0px 0px;
9.62 +table.preview td p {
9.63 + margin: 0px 5px 5px 5px;
9.64 }
9.65
9.66 .question, .question-options {
9.67 + background-color: #dddddd;
9.68 + color: #000000;
9.69 + vertical-align: top;
9.70 +}
9.71 +
9.72 +.question .control {
9.73 + font-weight: normal;
9.74 +}
9.75 +
9.76 +.response, .response-options {
9.77 background-color: #ffffff;
9.78 color: #000000;
9.79 vertical-align: top;
9.80 }
9.81
9.82 -.response, .response-options {
9.83 +.choice, .choice-options {
9.84 background-color: #eeeeee;
9.85 color: #000000;
9.86 vertical-align: top;
9.87 }
9.88 -
9.89 -.choice, .choice-options {
9.90 - background-color: #dddddd;
9.91 - color: #000000;
9.92 - vertical-align: top;
9.93 -}
10.1 --- a/examples/Common/Questionnaire/__init__.py Sun Nov 16 01:19:33 2008 +0100
10.2 +++ b/examples/Common/Questionnaire/__init__.py Mon Nov 17 01:50:18 2008 +0100
10.3 @@ -4,8 +4,10 @@
10.4
10.5 import WebStack.Generic
10.6 from XSLForms.Resources.WebResources import \
10.7 - XSLFormsResource, output, resources, prepare_resources as xslforms_prepare_resources
10.8 + XSLFormsResource, input, output, resources, prepare_resources as xslforms_prepare_resources
10.9 import os
10.10 +import libxml2dom
10.11 +import xml.dom
10.12
10.13 # Site map imports.
10.14
10.15 @@ -27,6 +29,12 @@
10.16 template_resources = {
10.17 "questionnaire" : output("question_template.xhtml")
10.18 }
10.19 + init_resources = {
10.20 + "questionnaire" : input("question_template.xhtml")
10.21 + }
10.22 + document_resources = {
10.23 + "response-types" : "question_response_types.xml"
10.24 + }
10.25
10.26 def select_activity(self, trans, form):
10.27 form.set_activity("questionnaire")
10.28 @@ -41,6 +49,25 @@
10.29 self.add_elements(selectors.get("add-choice"), "choice")
10.30 self.remove_elements(selectors.get("remove-choice"))
10.31
10.32 + # Move questions.
10.33 + # NOTE: Potentially a DOM convenience method here.
10.34 +
10.35 + for question in selectors.get("move-question", []):
10.36 + destination = int(question.getAttribute("destination"))
10.37 + if destination > 1:
10.38 + destination += 1
10.39 + root = questionnaire.documentElement
10.40 + target = (root.xpath("question[position() = %d]" % destination) or [None])[0]
10.41 + root.removeChild(question)
10.42 + if target is not None:
10.43 + try:
10.44 + root.insertBefore(question, target)
10.45 + except xml.dom.NotFoundErr:
10.46 + target = (root.xpath("question[position() = %d]" % destination) or [None])[0]
10.47 + root.insertBefore(question, target)
10.48 + else:
10.49 + root.appendChild(question)
10.50 +
10.51 # Add questions using the normal request parameter.
10.52
10.53 if parameters.has_key("add-question"):
10.54 @@ -55,6 +82,23 @@
10.55 questionnaire.toStream(trans.get_response_stream(), trans.get_response_stream_encoding())
10.56 raise WebStack.Generic.EndOfResponse
10.57
10.58 + # Support uploading of files.
10.59 +
10.60 + if parameters.has_key("import"):
10.61 + importfile = parameters["importfile"][0]
10.62 + try:
10.63 + doc = libxml2dom.parse(importfile.stream)
10.64 + form.set_document(doc)
10.65 + except libxml2dom.LSException:
10.66 + pass
10.67 +
10.68 + def init_document(self, trans, form):
10.69 +
10.70 + # Transform, adding enumerations/ranges.
10.71 +
10.72 + response_types_xml = self.prepare_document("response-types")
10.73 + XSLFormsResource.init_document(self, trans, form, references={"response-type" : response_types_xml})
10.74 +
10.75 # Site map initialisation.
10.76
10.77 def get_site():