XSLTools

Annotated XSLForms/Resources.py

178:7e7d9dbcec62
2005-07-22 paulb [project @ 2005-07-22 18:26:38 by paulb] Tidied up the function names and added some API documentation. Added child-element and child-attribute functions for coherent references to potentially non-existent nodes in the form data.
paulb@81 1
#!/usr/bin/env python
paulb@81 2
paulb@116 3
"""
paulb@116 4
Resources for use with WebStack.
paulb@116 5
paulb@116 6
Copyright (C) 2005 Paul Boddie <paul@boddie.org.uk>
paulb@116 7
paulb@116 8
This library is free software; you can redistribute it and/or
paulb@116 9
modify it under the terms of the GNU Lesser General Public
paulb@116 10
License as published by the Free Software Foundation; either
paulb@116 11
version 2.1 of the License, or (at your option) any later version.
paulb@116 12
paulb@116 13
This library is distributed in the hope that it will be useful,
paulb@116 14
but WITHOUT ANY WARRANTY; without even the implied warranty of
paulb@116 15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
paulb@116 16
Lesser General Public License for more details.
paulb@116 17
paulb@116 18
You should have received a copy of the GNU Lesser General Public
paulb@116 19
License along with this library; if not, write to the Free Software
paulb@116 20
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
paulb@116 21
"""
paulb@81 22
paulb@81 23
import WebStack.Generic
paulb@81 24
import XSLForms.Fields
paulb@83 25
import XSLForms.Prepare
paulb@83 26
import XSLForms.Output
paulb@83 27
import XSLOutput
paulb@83 28
import os
paulb@81 29
paulb@81 30
class XSLFormsResource:
paulb@81 31
paulb@83 32
    """
paulb@83 33
    A generic XSLForms resource for use with WebStack.
paulb@83 34
paulb@83 35
    When overriding this class, define the following attributes appropriately:
paulb@83 36
paulb@83 37
      * template_resources    - a dictionary mapping output identifiers to
paulb@83 38
                                (template_filename, output_filename) tuples,
paulb@83 39
                                indicating the template and stylesheet filenames
paulb@83 40
                                to be employed
paulb@83 41
paulb@83 42
      * in_page_resources     - a dictionary mapping fragment identifiers to
paulb@83 43
                                (output_filename, node_identifier) tuples,
paulb@83 44
                                indicating the stylesheet filename to be
paulb@83 45
                                employed, along with the node identifier used in
paulb@83 46
                                the original template and output documents to
paulb@83 47
                                mark a region of those documents as the fragment
paulb@83 48
                                to be updated upon "in-page" requests
paulb@83 49
paulb@146 50
      * transform_resources   - a dictionary mapping transform identifiers to
paulb@146 51
                                lists of stylesheet filenames for use with the
paulb@146 52
                                transformation methods
paulb@146 53
paulb@146 54
      * document_resources    - a dictionary mapping document identifiers to
paulb@146 55
                                single filenames for use as source documents or
paulb@146 56
                                as references with the transformation methods
paulb@146 57
paulb@83 58
      * resource_dir          - the absolute path of the directory in which
paulb@83 59
                                stylesheet resources are to reside
paulb@83 60
paulb@83 61
    All filenames shall be simple leafnames for files residing in the resource's
paulb@83 62
    special resource directory 'resource_dir'.
paulb@83 63
paulb@83 64
    The following attributes may also be specified:
paulb@83 65
paulb@83 66
      * path_encoding         - the assumed encoding of characters in request
paulb@83 67
                                paths
paulb@83 68
paulb@83 69
      * encoding              - the assumed encoding of characters in request
paulb@83 70
                                bodies
paulb@83 71
    """
paulb@81 72
paulb@81 73
    path_encoding = "iso-8859-1"
paulb@81 74
    encoding = "utf-8"
paulb@83 75
    template_resources = {}
paulb@83 76
    in_page_resources = {}
paulb@146 77
    transform_resources = {}
paulb@146 78
    document_resources = {}
paulb@83 79
    resource_dir = None
paulb@81 80
paulb@81 81
    def get_fields_from_body(self, trans, encoding):
paulb@81 82
paulb@81 83
        """
paulb@81 84
        From the given transaction 'trans' and using the stated text 'encoding'
paulb@81 85
        get the field values from the request body and return a dictionary
paulb@81 86
        mapping field names to lists of such values.
paulb@81 87
        """
paulb@81 88
paulb@81 89
        text = trans.get_request_stream().read().decode(encoding)
paulb@81 90
        parameters = {}
paulb@81 91
        for text_line in text.split("\r\n"):
paulb@81 92
            text_parts = text_line.split("=")
paulb@81 93
            text_name, text_value = text_parts[0], "=".join(text_parts[1:])
paulb@81 94
            if not parameters.has_key(text_name):
paulb@81 95
                parameters[text_name] = []
paulb@81 96
            # NOTE: Workaround from posted text.
paulb@161 97
            if len(text_value) > 0 and text_value[-1] == "\x00":
paulb@81 98
                text_value = text_value[:-1]
paulb@81 99
            parameters[text_name].append(text_value)
paulb@81 100
        return parameters
paulb@81 101
paulb@83 102
    def prepare_output(self, output_identifier):
paulb@83 103
paulb@83 104
        """
paulb@83 105
        Prepare the output stylesheets using the given 'output_identifier' to
paulb@83 106
        indicate which templates and stylesheets are to be employed in the
paulb@83 107
        production of output from the resource.
paulb@83 108
paulb@83 109
        The 'output_identifier' is used as a key to the 'template_resources'
paulb@83 110
        dictionary attribute.
paulb@146 111
paulb@146 112
        Return the full path to the output stylesheet for use with 'send_output'
paulb@146 113
        or 'get_result'.
paulb@83 114
        """
paulb@83 115
paulb@83 116
        template_filename, output_filename = self.template_resources[output_identifier]
paulb@83 117
        output_path = os.path.join(self.resource_dir, output_filename)
paulb@83 118
        template_path = os.path.join(self.resource_dir, template_filename)
paulb@83 119
        XSLForms.Prepare.ensure_stylesheet(template_path, output_path)
paulb@83 120
        return output_path
paulb@83 121
paulb@83 122
    def prepare_fragment(self, output_identifier, fragment_identifier):
paulb@83 123
paulb@83 124
        """
paulb@83 125
        Prepare the output stylesheets for the given 'output_identifier' and
paulb@83 126
        'fragment_identifier', indicating which templates and stylesheets are to
paulb@83 127
        be employed in the production of output from the resource.
paulb@83 128
paulb@83 129
        The 'output_identifier' is used as a key to the 'template_resources'
paulb@83 130
        dictionary attribute; the 'fragment_identifier' is used as a key to the
paulb@83 131
        'in_page_resources' dictionary attribute.
paulb@146 132
paulb@146 133
        Return the full path to the output stylesheet for use with 'send_output'
paulb@146 134
        or 'get_result'.
paulb@83 135
        """
paulb@83 136
paulb@83 137
        output_path = self.prepare_output(output_identifier)
paulb@83 138
        fragment_filename, node_identifier = self.in_page_resources[fragment_identifier]
paulb@83 139
        fragment_path = os.path.join(self.resource_dir, fragment_filename)
paulb@83 140
        XSLForms.Prepare.ensure_stylesheet_fragment(output_path, fragment_path, node_identifier)
paulb@83 141
        return fragment_path
paulb@83 142
paulb@146 143
    def send_output(self, trans, stylesheet_filenames, document, stylesheet_parameters=None, references=None):
paulb@83 144
paulb@83 145
        """
paulb@83 146
        Send the output from the resource to the user employing the transaction
paulb@85 147
        'trans', stylesheets having the given 'stylesheet_filenames', the
paulb@146 148
        'document' upon which the output will be based, the optional parameters
paulb@146 149
        as defined in the 'stylesheet_parameters' dictionary, and the optional
paulb@146 150
        'references' to external documents.
paulb@146 151
        """
paulb@146 152
paulb@146 153
        proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters, references=references)
paulb@146 154
        proc.send_output(trans.get_response_stream(), trans.get_response_stream_encoding(),
paulb@146 155
            document)
paulb@146 156
paulb@146 157
    def get_result(self, stylesheet_filenames, document, stylesheet_parameters=None, references=None):
paulb@146 158
paulb@146 159
        """
paulb@146 160
        Get the result of applying a transformation using stylesheets with the
paulb@146 161
        given 'stylesheet_filenames', the 'document' upon which the result will
paulb@146 162
        be based, the optional parameters as defined in the
paulb@146 163
        'stylesheet_parameters' dictionary, and the optional 'references' to
paulb@146 164
        external documents.
paulb@83 165
        """
paulb@83 166
paulb@146 167
        proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters, references=references)
paulb@146 168
        return proc.get_result(document)
paulb@146 169
paulb@146 170
    def prepare_transform(self, transform_identifier):
paulb@146 171
paulb@146 172
        """
paulb@146 173
        Prepare a transformation using the given 'transform_identifier'.
paulb@146 174
paulb@146 175
        Return a list of full paths to the output stylesheets for use with
paulb@146 176
        'send_output' or 'get_result'.
paulb@146 177
        """
paulb@146 178
paulb@146 179
        filenames = self.transform_resources[transform_identifier]
paulb@146 180
        paths = []
paulb@146 181
        for filename in filenames:
paulb@146 182
            paths.append(os.path.join(self.resource_dir, filename))
paulb@146 183
        return paths
paulb@146 184
paulb@146 185
    def prepare_document(self, document_identifier):
paulb@146 186
paulb@146 187
        """
paulb@146 188
        Prepare a document using the given 'document_identifier'.
paulb@146 189
paulb@146 190
        Return the full path of the document for use either as the source
paulb@146 191
        document or as a reference with 'send_output' or 'get_result'.
paulb@146 192
        """
paulb@146 193
paulb@146 194
        filename = self.document_resources[document_identifier]
paulb@146 195
        return os.path.join(self.resource_dir, filename)
paulb@83 196
paulb@110 197
    def get_in_page_resource(self, trans):
paulb@110 198
paulb@110 199
        """
paulb@110 200
        Return the in-page resource being referred to in the given transaction
paulb@110 201
        'trans'.
paulb@110 202
        """
paulb@110 203
paulb@110 204
        return trans.get_path_info().split("/")[-1]
paulb@110 205
paulb@81 206
    def respond(self, trans):
paulb@81 207
paulb@81 208
        """
paulb@81 209
        Respond to the request described by the given transaction 'trans'.
paulb@81 210
        """
paulb@81 211
paulb@81 212
        # Only obtain field information according to the stated method.
paulb@81 213
paulb@81 214
        method = trans.get_request_method()
paulb@110 215
        in_page_resource = self.get_in_page_resource(trans)
paulb@81 216
paulb@81 217
        # Handle typical request methods, processing request information.
paulb@81 218
paulb@81 219
        if method == "GET":
paulb@81 220
paulb@81 221
            # Get the fields from the request path (URL).
paulb@81 222
paulb@81 223
            form = XSLForms.Fields.Form(encoding=self.path_encoding, values_are_lists=1)
paulb@81 224
            parameters = trans.get_fields_from_path()
paulb@81 225
            form.set_parameters(parameters)
paulb@81 226
paulb@81 227
        elif method == "POST":
paulb@81 228
paulb@81 229
            # Get the fields from the request body.
paulb@81 230
paulb@81 231
            form = XSLForms.Fields.Form(encoding=self.encoding, values_are_lists=1)
paulb@81 232
paulb@81 233
            # Handle requests for in-page updates.
paulb@81 234
paulb@110 235
            if in_page_resource in self.in_page_resources.keys():
paulb@81 236
                parameters = self.get_fields_from_body(trans, self.encoding)
paulb@81 237
            else:
paulb@81 238
                parameters = trans.get_fields_from_body(self.encoding)
paulb@81 239
paulb@81 240
            # Get the XML representation of the request.
paulb@81 241
paulb@81 242
            form.set_parameters(parameters)
paulb@81 243
paulb@81 244
        else:
paulb@81 245
paulb@81 246
            # Initialise empty containers.
paulb@81 247
paulb@81 248
            parameters = {}
paulb@81 249
            documents = {}
paulb@81 250
paulb@81 251
        # Call an overridden method with the processed request information.
paulb@81 252
paulb@81 253
        self.respond_to_form(trans, form)
paulb@81 254
paulb@81 255
    def respond_to_form(self, trans, form):
paulb@81 256
paulb@81 257
        """
paulb@81 258
        Respond to the request described by the given transaction 'trans', using
paulb@81 259
        the given 'form' object to conveniently retrieve field (request
paulb@81 260
        parameter) information and structured form information (as DOM-style XML
paulb@81 261
        documents).
paulb@81 262
        """
paulb@81 263
paulb@81 264
        trans.set_response_code(500)
paulb@81 265
        raise WebStack.Generic.EndOfResponse
paulb@81 266
paulb@81 267
# vim: tabstop=4 expandtab shiftwidth=4