XSLTools

Annotated XSLForms/Resources.py

209:d908046cd1b0
2005-08-25 paulb [project @ 2005-08-25 13:37:49 by paulb] Introduced path encoding into get_path_info call.
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@202 27
from XSLTools 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@193 81
    def clean_parameters(self, parameters):
paulb@81 82
paulb@81 83
        """
paulb@193 84
        Workaround stray zero value characters from Konqueror in XMLHttpRequest
paulb@193 85
        communications.
paulb@81 86
        """
paulb@81 87
paulb@193 88
        for name, values in parameters.items():
paulb@193 89
            new_values = []
paulb@193 90
            for value in values:
paulb@193 91
                if value.endswith("\x00"):
paulb@193 92
                    new_values.append(value[:-1])
paulb@193 93
                else:
paulb@193 94
                    new_values.append(value)
paulb@193 95
            parameters[name] = new_values
paulb@81 96
paulb@83 97
    def prepare_output(self, output_identifier):
paulb@83 98
paulb@83 99
        """
paulb@83 100
        Prepare the output stylesheets using the given 'output_identifier' to
paulb@83 101
        indicate which templates and stylesheets are to be employed in the
paulb@83 102
        production of output from the resource.
paulb@83 103
paulb@83 104
        The 'output_identifier' is used as a key to the 'template_resources'
paulb@83 105
        dictionary attribute.
paulb@146 106
paulb@146 107
        Return the full path to the output stylesheet for use with 'send_output'
paulb@146 108
        or 'get_result'.
paulb@83 109
        """
paulb@83 110
paulb@83 111
        template_filename, output_filename = self.template_resources[output_identifier]
paulb@83 112
        output_path = os.path.join(self.resource_dir, output_filename)
paulb@83 113
        template_path = os.path.join(self.resource_dir, template_filename)
paulb@83 114
        XSLForms.Prepare.ensure_stylesheet(template_path, output_path)
paulb@83 115
        return output_path
paulb@83 116
paulb@83 117
    def prepare_fragment(self, output_identifier, fragment_identifier):
paulb@83 118
paulb@83 119
        """
paulb@83 120
        Prepare the output stylesheets for the given 'output_identifier' and
paulb@83 121
        'fragment_identifier', indicating which templates and stylesheets are to
paulb@83 122
        be employed in the production of output from the resource.
paulb@83 123
paulb@83 124
        The 'output_identifier' is used as a key to the 'template_resources'
paulb@83 125
        dictionary attribute; the 'fragment_identifier' is used as a key to the
paulb@83 126
        'in_page_resources' dictionary attribute.
paulb@146 127
paulb@146 128
        Return the full path to the output stylesheet for use with 'send_output'
paulb@146 129
        or 'get_result'.
paulb@83 130
        """
paulb@83 131
paulb@83 132
        output_path = self.prepare_output(output_identifier)
paulb@83 133
        fragment_filename, node_identifier = self.in_page_resources[fragment_identifier]
paulb@83 134
        fragment_path = os.path.join(self.resource_dir, fragment_filename)
paulb@83 135
        XSLForms.Prepare.ensure_stylesheet_fragment(output_path, fragment_path, node_identifier)
paulb@83 136
        return fragment_path
paulb@83 137
paulb@146 138
    def send_output(self, trans, stylesheet_filenames, document, stylesheet_parameters=None, references=None):
paulb@83 139
paulb@83 140
        """
paulb@83 141
        Send the output from the resource to the user employing the transaction
paulb@85 142
        'trans', stylesheets having the given 'stylesheet_filenames', the
paulb@146 143
        'document' upon which the output will be based, the optional parameters
paulb@146 144
        as defined in the 'stylesheet_parameters' dictionary, and the optional
paulb@146 145
        'references' to external documents.
paulb@146 146
        """
paulb@146 147
paulb@146 148
        proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters, references=references)
paulb@146 149
        proc.send_output(trans.get_response_stream(), trans.get_response_stream_encoding(),
paulb@146 150
            document)
paulb@146 151
paulb@146 152
    def get_result(self, stylesheet_filenames, document, stylesheet_parameters=None, references=None):
paulb@146 153
paulb@146 154
        """
paulb@146 155
        Get the result of applying a transformation using stylesheets with the
paulb@146 156
        given 'stylesheet_filenames', the 'document' upon which the result will
paulb@146 157
        be based, the optional parameters as defined in the
paulb@146 158
        'stylesheet_parameters' dictionary, and the optional 'references' to
paulb@146 159
        external documents.
paulb@83 160
        """
paulb@83 161
paulb@146 162
        proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters, references=references)
paulb@146 163
        return proc.get_result(document)
paulb@146 164
paulb@146 165
    def prepare_transform(self, transform_identifier):
paulb@146 166
paulb@146 167
        """
paulb@146 168
        Prepare a transformation using the given 'transform_identifier'.
paulb@146 169
paulb@146 170
        Return a list of full paths to the output stylesheets for use with
paulb@146 171
        'send_output' or 'get_result'.
paulb@146 172
        """
paulb@146 173
paulb@146 174
        filenames = self.transform_resources[transform_identifier]
paulb@146 175
        paths = []
paulb@146 176
        for filename in filenames:
paulb@146 177
            paths.append(os.path.join(self.resource_dir, filename))
paulb@146 178
        return paths
paulb@146 179
paulb@146 180
    def prepare_document(self, document_identifier):
paulb@146 181
paulb@146 182
        """
paulb@146 183
        Prepare a document using the given 'document_identifier'.
paulb@146 184
paulb@146 185
        Return the full path of the document for use either as the source
paulb@146 186
        document or as a reference with 'send_output' or 'get_result'.
paulb@146 187
        """
paulb@146 188
paulb@146 189
        filename = self.document_resources[document_identifier]
paulb@146 190
        return os.path.join(self.resource_dir, filename)
paulb@83 191
paulb@110 192
    def get_in_page_resource(self, trans):
paulb@110 193
paulb@110 194
        """
paulb@110 195
        Return the in-page resource being referred to in the given transaction
paulb@110 196
        'trans'.
paulb@110 197
        """
paulb@110 198
paulb@209 199
        return trans.get_path_info(self.path_encoding).split("/")[-1]
paulb@110 200
paulb@81 201
    def respond(self, trans):
paulb@81 202
paulb@81 203
        """
paulb@81 204
        Respond to the request described by the given transaction 'trans'.
paulb@81 205
        """
paulb@81 206
paulb@81 207
        # Only obtain field information according to the stated method.
paulb@81 208
paulb@81 209
        method = trans.get_request_method()
paulb@110 210
        in_page_resource = self.get_in_page_resource(trans)
paulb@81 211
paulb@81 212
        # Handle typical request methods, processing request information.
paulb@81 213
paulb@81 214
        if method == "GET":
paulb@81 215
paulb@81 216
            # Get the fields from the request path (URL).
paulb@209 217
            # NOTE: The encoding is actually redundant since WebStack produces
paulb@209 218
            # NOTE: Unicode values.
paulb@81 219
paulb@81 220
            form = XSLForms.Fields.Form(encoding=self.path_encoding, values_are_lists=1)
paulb@81 221
            parameters = trans.get_fields_from_path()
paulb@81 222
            form.set_parameters(parameters)
paulb@81 223
paulb@81 224
        elif method == "POST":
paulb@81 225
paulb@81 226
            # Get the fields from the request body.
paulb@209 227
            # NOTE: The encoding is actually redundant since WebStack produces
paulb@209 228
            # NOTE: Unicode values.
paulb@81 229
paulb@81 230
            form = XSLForms.Fields.Form(encoding=self.encoding, values_are_lists=1)
paulb@193 231
            parameters = trans.get_fields_from_body(self.encoding)
paulb@81 232
paulb@193 233
            # NOTE: Konqueror workaround.
paulb@193 234
            self.clean_parameters(parameters)
paulb@81 235
paulb@81 236
            form.set_parameters(parameters)
paulb@81 237
paulb@81 238
        else:
paulb@81 239
paulb@81 240
            # Initialise empty containers.
paulb@81 241
paulb@81 242
            parameters = {}
paulb@81 243
            documents = {}
paulb@81 244
paulb@81 245
        # Call an overridden method with the processed request information.
paulb@81 246
paulb@81 247
        self.respond_to_form(trans, form)
paulb@81 248
paulb@81 249
    def respond_to_form(self, trans, form):
paulb@81 250
paulb@81 251
        """
paulb@81 252
        Respond to the request described by the given transaction 'trans', using
paulb@81 253
        the given 'form' object to conveniently retrieve field (request
paulb@81 254
        parameter) information and structured form information (as DOM-style XML
paulb@81 255
        documents).
paulb@81 256
        """
paulb@81 257
paulb@81 258
        trans.set_response_code(500)
paulb@81 259
        raise WebStack.Generic.EndOfResponse
paulb@81 260
paulb@81 261
# vim: tabstop=4 expandtab shiftwidth=4