1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/XSLForms/Resources/WebResources.py Wed Oct 26 00:07:09 2005 +0000
1.3 @@ -0,0 +1,312 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +Resources for use with WebStack.
1.8 +
1.9 +Copyright (C) 2005 Paul Boddie <paul@boddie.org.uk>
1.10 +
1.11 +This library is free software; you can redistribute it and/or
1.12 +modify it under the terms of the GNU Lesser General Public
1.13 +License as published by the Free Software Foundation; either
1.14 +version 2.1 of the License, or (at your option) any later version.
1.15 +
1.16 +This library is distributed in the hope that it will be useful,
1.17 +but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1.19 +Lesser General Public License for more details.
1.20 +
1.21 +You should have received a copy of the GNU Lesser General Public
1.22 +License along with this library; if not, write to the Free Software
1.23 +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1.24 +"""
1.25 +
1.26 +import WebStack.Generic
1.27 +import XSLForms.Fields
1.28 +import XSLForms.Prepare
1.29 +import XSLForms.Output
1.30 +from XSLTools import XSLOutput
1.31 +import os
1.32 +
1.33 +class XSLFormsResource:
1.34 +
1.35 + """
1.36 + A generic XSLForms resource for use with WebStack.
1.37 +
1.38 + When overriding this class, define the following attributes appropriately:
1.39 +
1.40 + * template_resources - a dictionary mapping output identifiers to
1.41 + (template_filename, output_filename) tuples,
1.42 + indicating the template and stylesheet filenames
1.43 + to be employed
1.44 +
1.45 + * in_page_resources - a dictionary mapping fragment identifiers to
1.46 + (output_filename, node_identifier) tuples,
1.47 + indicating the stylesheet filename to be
1.48 + employed, along with the node identifier used in
1.49 + the original template and output documents to
1.50 + mark a region of those documents as the fragment
1.51 + to be updated upon "in-page" requests
1.52 +
1.53 + * init_resources - a dictionary mapping initialiser/input
1.54 + identifiers to (template_filename,
1.55 + input_filename) tuples, indicating the template
1.56 + and initialiser/input stylesheet filenames to be
1.57 + employed
1.58 +
1.59 + * transform_resources - a dictionary mapping transform identifiers to
1.60 + lists of stylesheet filenames for use with the
1.61 + transformation methods
1.62 +
1.63 + * document_resources - a dictionary mapping document identifiers to
1.64 + single filenames for use as source documents or
1.65 + as references with the transformation methods
1.66 +
1.67 + * resource_dir - the absolute path of the directory in which
1.68 + stylesheet resources are to reside
1.69 +
1.70 + All filenames shall be simple leafnames for files residing in the resource's
1.71 + special resource directory 'resource_dir'.
1.72 +
1.73 + The following attributes may also be specified:
1.74 +
1.75 + * path_encoding - the assumed encoding of characters in request
1.76 + paths
1.77 +
1.78 + * encoding - the assumed encoding of characters in request
1.79 + bodies
1.80 + """
1.81 +
1.82 + path_encoding = "utf-8"
1.83 + encoding = "utf-8"
1.84 + template_resources = {}
1.85 + in_page_resources = {}
1.86 + transform_resources = {}
1.87 + document_resources = {}
1.88 + resource_dir = None
1.89 +
1.90 + def clean_parameters(self, parameters):
1.91 +
1.92 + """
1.93 + Workaround stray zero value characters from Konqueror in XMLHttpRequest
1.94 + communications.
1.95 + """
1.96 +
1.97 + for name, values in parameters.items():
1.98 + new_values = []
1.99 + for value in values:
1.100 + if value.endswith("\x00"):
1.101 + new_values.append(value[:-1])
1.102 + else:
1.103 + new_values.append(value)
1.104 + parameters[name] = new_values
1.105 +
1.106 + def prepare_output(self, output_identifier):
1.107 +
1.108 + """
1.109 + Prepare the output stylesheets using the given 'output_identifier' to
1.110 + indicate which templates and stylesheets are to be employed in the
1.111 + production of output from the resource.
1.112 +
1.113 + The 'output_identifier' is used as a key to the 'template_resources'
1.114 + dictionary attribute.
1.115 +
1.116 + Return the full path to the output stylesheet for use with 'send_output'
1.117 + or 'get_result'.
1.118 + """
1.119 +
1.120 + template_filename, output_filename = self.template_resources[output_identifier]
1.121 + output_path = os.path.abspath(os.path.join(self.resource_dir, output_filename))
1.122 + template_path = os.path.abspath(os.path.join(self.resource_dir, template_filename))
1.123 + XSLForms.Prepare.ensure_stylesheet(template_path, output_path)
1.124 + return output_path
1.125 +
1.126 + def prepare_fragment(self, output_identifier, fragment_identifier):
1.127 +
1.128 + """
1.129 + Prepare the output stylesheets for the given 'output_identifier' and
1.130 + 'fragment_identifier', indicating which templates and stylesheets are to
1.131 + be employed in the production of output from the resource.
1.132 +
1.133 + The 'output_identifier' is used as a key to the 'template_resources'
1.134 + dictionary attribute; the 'fragment_identifier' is used as a key to the
1.135 + 'in_page_resources' dictionary attribute.
1.136 +
1.137 + Return the full path to the output stylesheet for use with 'send_output'
1.138 + or 'get_result'.
1.139 + """
1.140 +
1.141 + output_path = self.prepare_output(output_identifier)
1.142 + fragment_filename, node_identifier = self.in_page_resources[fragment_identifier]
1.143 + fragment_path = os.path.abspath(os.path.join(self.resource_dir, fragment_filename))
1.144 + XSLForms.Prepare.ensure_stylesheet_fragment(output_path, fragment_path, node_identifier)
1.145 + return fragment_path
1.146 +
1.147 + def prepare_parameters(self, parameters):
1.148 +
1.149 + """
1.150 + Prepare the stylesheet parameters from the given request 'parameters'.
1.151 + This is most useful when preparing fragments for in-page update output.
1.152 + """
1.153 +
1.154 + element_path = parameters.get("element-path", [""])[0]
1.155 + if element_path:
1.156 + return {"element-path" : element_path}
1.157 + else:
1.158 + return {}
1.159 +
1.160 + def send_output(self, trans, stylesheet_filenames, document, stylesheet_parameters=None,
1.161 + stylesheet_expressions=None, references=None):
1.162 +
1.163 + """
1.164 + Send the output from the resource to the user employing the transaction
1.165 + 'trans', stylesheets having the given 'stylesheet_filenames', the
1.166 + 'document' upon which the output will be based, the optional parameters
1.167 + as defined in the 'stylesheet_parameters' dictionary, the optional
1.168 + expressions are defined in the 'stylesheet_expressions' dictionary, and
1.169 + the optional 'references' to external documents.
1.170 + """
1.171 +
1.172 + # Sanity check for the filenames list.
1.173 +
1.174 + if isinstance(stylesheet_filenames, str) or isinstance(stylesheet_filenames, unicode):
1.175 + raise ValueError, stylesheet_filenames
1.176 +
1.177 + proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters,
1.178 + expressions=stylesheet_expressions, references=references)
1.179 + proc.send_output(trans.get_response_stream(), trans.get_response_stream_encoding(),
1.180 + document)
1.181 +
1.182 + def get_result(self, stylesheet_filenames, document, stylesheet_parameters=None,
1.183 + stylesheet_expressions=None, references=None):
1.184 +
1.185 + """
1.186 + Get the result of applying a transformation using stylesheets with the
1.187 + given 'stylesheet_filenames', the 'document' upon which the result will
1.188 + be based, the optional parameters as defined in the
1.189 + 'stylesheet_parameters' dictionary, the optional parameters as defined
1.190 + in the 'stylesheet_parameters' dictionaryand the optional 'references'
1.191 + to external documents.
1.192 + """
1.193 +
1.194 + # Sanity check for the filenames list.
1.195 +
1.196 + if isinstance(stylesheet_filenames, str) or isinstance(stylesheet_filenames, unicode):
1.197 + raise ValueError, stylesheet_filenames
1.198 +
1.199 + proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters,
1.200 + expressions=stylesheet_expressions, references=references)
1.201 + return proc.get_result(document)
1.202 +
1.203 + def prepare_initialiser(self, input_identifier):
1.204 +
1.205 + """
1.206 + Prepare an initialiser/input transformation using the given
1.207 + 'input_identifier'.
1.208 +
1.209 + Return the full path to the input stylesheet for use with 'send_output'
1.210 + or 'get_result'.
1.211 + """
1.212 +
1.213 + template_filename, input_filename = self.init_resources[input_identifier]
1.214 + input_path = os.path.abspath(os.path.join(self.resource_dir, input_filename))
1.215 + template_path = os.path.abspath(os.path.join(self.resource_dir, template_filename))
1.216 + XSLForms.Prepare.ensure_input_stylesheet(template_path, input_path)
1.217 + return input_path
1.218 +
1.219 + def prepare_transform(self, transform_identifier):
1.220 +
1.221 + """
1.222 + Prepare a transformation using the given 'transform_identifier'.
1.223 +
1.224 + Return a list of full paths to the output stylesheets for use with
1.225 + 'send_output' or 'get_result'.
1.226 + """
1.227 +
1.228 + filenames = self.transform_resources[transform_identifier]
1.229 + paths = []
1.230 + for filename in filenames:
1.231 + paths.append(os.path.abspath(os.path.join(self.resource_dir, filename)))
1.232 + return paths
1.233 +
1.234 + def prepare_document(self, document_identifier):
1.235 +
1.236 + """
1.237 + Prepare a document using the given 'document_identifier'.
1.238 +
1.239 + Return the full path of the document for use either as the source
1.240 + document or as a reference with 'send_output' or 'get_result'.
1.241 + """
1.242 +
1.243 + filename = self.document_resources[document_identifier]
1.244 + return os.path.abspath(os.path.join(self.resource_dir, filename))
1.245 +
1.246 + def get_in_page_resource(self, trans):
1.247 +
1.248 + """
1.249 + Return the in-page resource being referred to in the given transaction
1.250 + 'trans'.
1.251 + """
1.252 +
1.253 + return trans.get_path_info(self.path_encoding).split("/")[-1]
1.254 +
1.255 + def respond(self, trans):
1.256 +
1.257 + """
1.258 + Respond to the request described by the given transaction 'trans'.
1.259 + """
1.260 +
1.261 + # Only obtain field information according to the stated method.
1.262 +
1.263 + method = trans.get_request_method()
1.264 + in_page_resource = self.get_in_page_resource(trans)
1.265 +
1.266 + # Handle typical request methods, processing request information.
1.267 +
1.268 + if method == "GET":
1.269 +
1.270 + # Get the fields from the request path (URL).
1.271 + # NOTE: The encoding is actually redundant since WebStack produces
1.272 + # NOTE: Unicode values.
1.273 +
1.274 + form = XSLForms.Fields.Form(encoding=self.path_encoding, values_are_lists=1)
1.275 + parameters = trans.get_fields_from_path()
1.276 + form.set_parameters(parameters)
1.277 +
1.278 + elif method == "POST":
1.279 +
1.280 + # Get the fields from the request body.
1.281 + # NOTE: The encoding is actually redundant since WebStack produces
1.282 + # NOTE: Unicode values.
1.283 +
1.284 + form = XSLForms.Fields.Form(encoding=self.encoding, values_are_lists=1)
1.285 + parameters = trans.get_fields_from_body(self.encoding)
1.286 +
1.287 + # NOTE: Konqueror workaround.
1.288 + self.clean_parameters(parameters)
1.289 +
1.290 + form.set_parameters(parameters)
1.291 +
1.292 + else:
1.293 +
1.294 + # Initialise empty containers.
1.295 +
1.296 + parameters = {}
1.297 + documents = {}
1.298 +
1.299 + # Call an overridden method with the processed request information.
1.300 +
1.301 + self.respond_to_form(trans, form)
1.302 +
1.303 + def respond_to_form(self, trans, form):
1.304 +
1.305 + """
1.306 + Respond to the request described by the given transaction 'trans', using
1.307 + the given 'form' object to conveniently retrieve field (request
1.308 + parameter) information and structured form information (as DOM-style XML
1.309 + documents).
1.310 + """
1.311 +
1.312 + trans.set_response_code(500)
1.313 + raise WebStack.Generic.EndOfResponse
1.314 +
1.315 +# vim: tabstop=4 expandtab shiftwidth=4