XSLTools

XSLForms/Resources/WebResources.py

534:a57218cde853
2006-11-11 paulb [project @ 2006-11-11 01:43:16 by paulb] Introduced a content type check to avoid needless discarding of non-form data.
     1 #!/usr/bin/env python     2      3 """     4 Resources for use with WebStack.     5      6 Copyright (C) 2005 Paul Boddie <paul@boddie.org.uk>     7      8 This library is free software; you can redistribute it and/or     9 modify it under the terms of the GNU Lesser General Public    10 License as published by the Free Software Foundation; either    11 version 2.1 of the License, or (at your option) any later version.    12     13 This library is distributed in the hope that it will be useful,    14 but WITHOUT ANY WARRANTY; without even the implied warranty of    15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    16 Lesser General Public License for more details.    17     18 You should have received a copy of the GNU Lesser General Public    19 License along with this library; if not, write to the Free Software    20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA    21 """    22     23 import WebStack.Generic    24 import XSLForms.Fields    25 import XSLForms.Prepare    26 import XSLForms.Output    27 import XSLForms.Resources.Common    28 from XSLTools import XSLOutput    29 import os    30     31 class XSLFormsResource(XSLForms.Resources.Common.CommonResource):    32     33     """    34     A generic XSLForms resource for use with WebStack.    35     36     When overriding this class, define the following attributes appropriately:    37     38       * template_resources    - a dictionary mapping output identifiers to    39                                 (template_filename, output_filename) tuples,    40                                 indicating the template and stylesheet filenames    41                                 to be employed    42     43       * in_page_resources     - a dictionary mapping fragment identifiers to    44                                 (output_identifier, output_filename,    45                                 node_identifier) tuples, indicating the output    46                                 identifier for which the fragment applies, the    47                                 stylesheet filename to be employed, along with    48                                 the node identifier used in the original    49                                 template and output documents to mark a region    50                                 of those documents as the fragment to be updated    51                                 upon "in-page" requests    52     53       * init_resources        - a dictionary mapping initialiser/input    54                                 identifiers to (template_filename,    55                                 input_filename) tuples, indicating the template    56                                 and initialiser/input stylesheet filenames to be    57                                 employed    58                                     59       * transform_resources   - a dictionary mapping transform identifiers to    60                                 lists of stylesheet filenames for use with the    61                                 transformation methods    62     63       * document_resources    - a dictionary mapping document identifiers to    64                                 single filenames for use as source documents or    65                                 as references with the transformation methods    66     67       * resource_dir          - the absolute path of the directory in which    68                                 stylesheet resources are to reside    69     70     All filenames shall be simple leafnames for files residing in the resource's    71     special resource directory 'resource_dir'.    72     73     The following attributes may also be specified:    74     75       * path_encoding         - the assumed encoding of characters in request    76                                 paths    77     78       * encoding              - the assumed encoding of characters in request    79                                 bodies    80     """    81     82     path_encoding = "utf-8"    83     encoding = "utf-8"    84     template_resources = {}    85     in_page_resources = {}    86     init_resources = {}    87     transform_resources = {}    88     89     def clean_parameters(self, parameters):    90     91         """    92         Workaround stray zero value characters from Konqueror in XMLHttpRequest    93         communications.    94         """    95     96         for name, values in parameters.items():    97             new_values = []    98             for value in values:    99                 if value.endswith("\x00"):   100                     new_values.append(value[:-1])   101                 else:   102                     new_values.append(value)   103             parameters[name] = new_values   104    105     def prepare_output(self, output_identifier):   106    107         """   108         Prepare the output stylesheets using the given 'output_identifier' to   109         indicate which templates and stylesheets are to be employed in the   110         production of output from the resource.   111    112         The 'output_identifier' is used as a key to the 'template_resources'   113         dictionary attribute.   114    115         Return the full path to the output stylesheet for use with 'send_output'   116         or 'get_result'.   117         """   118    119         template_path, output_path = prepare_output(self, output_identifier)   120         return output_path   121    122     def prepare_fragment(self, fragment_identifier):   123    124         """   125         Prepare the output stylesheets for the given 'fragment_identifier',   126         indicating which templates and stylesheets are to be employed in the   127         production of output from the resource.   128    129         The 'fragment_identifier' is used as a key to the 'in_page_resources'   130         dictionary attribute which in turn obtains an 'output_identifier', which   131         is used as a key to the 'template_resources' dictionary attribute.   132    133         Return the full path to the output stylesheet for use with 'send_output'   134         or 'get_result'.   135         """   136    137         template_path, fragment_path = prepare_fragment(self, fragment_identifier)   138         return fragment_path   139    140     def prepare_parameters(self, parameters):   141    142         """   143         Prepare the stylesheet parameters from the given request 'parameters'.   144         This is most useful when preparing fragments for in-page update output.   145         """   146    147         element_path = parameters.get("element-path", [""])[0]   148         if element_path:   149             return {"element-path" : element_path}   150         else:   151             return {}   152    153     def send_output(self, trans, stylesheet_filenames, document, stylesheet_parameters=None,   154         stylesheet_expressions=None, references=None):   155    156         """   157         Send the output from the resource to the user employing the transaction   158         'trans', stylesheets having the given 'stylesheet_filenames', the   159         'document' upon which the output will be based, the optional parameters   160         as defined in the 'stylesheet_parameters' dictionary, the optional   161         expressions are defined in the 'stylesheet_expressions' dictionary, and   162         the optional 'references' to external documents.   163         """   164    165         # Sanity check for the filenames list.   166    167         if isinstance(stylesheet_filenames, str) or isinstance(stylesheet_filenames, unicode):   168             raise ValueError, stylesheet_filenames   169    170         proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters,   171             expressions=stylesheet_expressions, references=references)   172         proc.send_output(trans.get_response_stream(), trans.get_response_stream_encoding(),   173             document)   174    175     def get_result(self, stylesheet_filenames, document, stylesheet_parameters=None,   176         stylesheet_expressions=None, references=None):   177    178         """   179         Get the result of applying a transformation using stylesheets with the   180         given 'stylesheet_filenames', the 'document' upon which the result will   181         be based, the optional parameters as defined in the   182         'stylesheet_parameters' dictionary, the optional parameters as defined   183         in the 'stylesheet_parameters' dictionary and the optional 'references'   184         to external documents.   185         """   186    187         # Sanity check for the filenames list.   188    189         if isinstance(stylesheet_filenames, str) or isinstance(stylesheet_filenames, unicode):   190             raise ValueError, stylesheet_filenames   191    192         proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters,   193             expressions=stylesheet_expressions, references=references)   194         return proc.get_result(document)   195    196     def prepare_initialiser(self, input_identifier, init_enumerations=1):   197    198         """   199         Prepare an initialiser/input transformation using the given   200         'input_identifier'. The optional 'init_enumerations' (defaulting to   201         true) may be used to indicate whether enumerations are to be initialised   202         from external documents.   203    204         Return the full path to the input stylesheet for use with 'send_output'   205         or 'get_result'.   206         """   207    208         template_path, input_path = prepare_initialiser(self, input_identifier, init_enumerations)   209         return input_path   210    211     def prepare_transform(self, transform_identifier):   212    213         """   214         Prepare a transformation using the given 'transform_identifier'.   215    216         Return a list of full paths to the output stylesheets for use with   217         'send_output' or 'get_result'.   218         """   219    220         filenames = self.transform_resources[transform_identifier]   221    222         # Sanity check for the filenames list.   223    224         if isinstance(filenames, str) or isinstance(filenames, unicode):   225             raise ValueError, filenames   226    227         paths = []   228         for filename in filenames:   229             paths.append(os.path.abspath(os.path.join(self.resource_dir, filename)))   230         return paths   231    232     def get_in_page_resource(self, trans):   233    234         """   235         Return the in-page resource being referred to in the given transaction   236         'trans'.   237         """   238    239         return trans.get_path_info(self.path_encoding).split("/")[-1]   240    241     def respond(self, trans):   242    243         """   244         Respond to the request described by the given transaction 'trans'.   245         """   246    247         # Only obtain field information according to the stated method.   248    249         content_type = trans.get_content_type()   250         method = trans.get_request_method()   251         in_page_resource = self.get_in_page_resource(trans)   252    253         # Handle typical request methods, processing request information.   254    255         if method == "GET":   256    257             # Get the fields from the request path (URL).   258             # NOTE: The encoding is actually redundant since WebStack produces   259             # NOTE: Unicode values.   260    261             form = XSLForms.Fields.Form(encoding=self.path_encoding, values_are_lists=1)   262             parameters = trans.get_fields_from_path()   263             form.set_parameters(parameters)   264    265         elif method == "POST" and content_type.media_type == "application/x-www-form-urlencoded":   266    267             # Get the fields from the request body.   268             # NOTE: The encoding is actually redundant since WebStack produces   269             # NOTE: Unicode values.   270    271             form = XSLForms.Fields.Form(encoding=self.encoding, values_are_lists=1)   272             parameters = trans.get_fields_from_body(self.encoding)   273    274             # NOTE: Konqueror workaround.   275             self.clean_parameters(parameters)   276    277             form.set_parameters(parameters)   278    279         else:   280    281             # Initialise empty container.   282    283             form = XSLForms.Fields.Form(encoding=self.encoding, values_are_lists=1)   284    285         # Call an overridden method with the processed request information.   286    287         self.respond_to_form(trans, form)   288    289     def respond_to_form(self, trans, form):   290    291         """   292         Respond to the request described by the given transaction 'trans', using   293         the given 'form' object to conveniently retrieve field (request   294         parameter) information and structured form information (as DOM-style XML   295         documents).   296         """   297    298         trans.set_response_code(500)   299         trans.set_content_type(WebStack.Generic.ContentType("text/plain"))   300         out = trans.get_response_stream()   301         out.write("Resource not fully defined to respond.")   302         raise WebStack.Generic.EndOfResponse   303    304 def prepare_output(self, output_identifier):   305    306     """   307     Prepare the output stylesheet for the resource class or object 'self'   308     corresponding to the given 'output_identifier'. Return the template path   309     and the output stylesheet path in a 2-tuple.   310     """   311    312     template_filename, output_filename = self.template_resources[output_identifier]   313     output_path = os.path.abspath(os.path.join(self.resource_dir, output_filename))   314     template_path = os.path.abspath(os.path.join(self.resource_dir, template_filename))   315     XSLForms.Prepare.ensure_stylesheet(template_path, output_path)   316     return template_path, output_path   317    318 def prepare_fragment(self, fragment_identifier):   319    320     """   321     Prepare the output stylesheet for the resource class or object 'self'   322     corresponding to the given 'fragment_identifier'. Return the template path   323     and the output stylesheet path in a 2-tuple.   324     """   325    326     output_identifier, fragment_filename, node_identifier = self.in_page_resources[fragment_identifier]   327     fragment_path = os.path.abspath(os.path.join(self.resource_dir, fragment_filename))   328     template_filename, output_filename = self.template_resources[output_identifier]   329     template_path = os.path.abspath(os.path.join(self.resource_dir, template_filename))   330     XSLForms.Prepare.ensure_stylesheet_fragment(template_path, fragment_path, node_identifier)   331     return template_path, fragment_path   332    333 def prepare_initialiser(self, input_identifier, init_enumerations):   334    335     """   336     Prepare the initialising stylesheet for the resource class or object 'self'   337     corresponding to the given 'input_identifier' and 'init_enumerations' flag.   338     Return the template path and the initialising stylesheet path in a 2-tuple.   339     """   340    341     template_filename, input_filename = self.init_resources[input_identifier]   342     input_path = os.path.abspath(os.path.join(self.resource_dir, input_filename))   343     template_path = os.path.abspath(os.path.join(self.resource_dir, template_filename))   344     XSLForms.Prepare.ensure_input_stylesheet(template_path, input_path, init_enumerations)   345     return template_path, input_path   346    347 def prepare_resources(cls):   348    349     "Prepare the resources associated with the class 'cls'."   350    351     for output_identifier in cls.template_resources.keys():   352         prepare_output(cls, output_identifier)   353     for fragment_identifier in cls.in_page_resources.keys():   354         prepare_fragment(cls, fragment_identifier)   355    356     # NOTE: Using init_enumerations=1 here.   357    358     for input_identifier in cls.init_resources.keys():   359         prepare_initialiser(cls, input_identifier, 1)   360    361 # vim: tabstop=4 expandtab shiftwidth=4