XSLTools

docs/Web-resource.html

377:7fb43f2befb0
2005-11-01 paulb [project @ 2005-11-01 18:58:15 by paulb] Added memory and storage unit initialisation.
     1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">     2 <html xmlns="http://www.w3.org/1999/xhtml"><head>     3   <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type" />     4        5   <title>Creating Applications: Write a Web Resource</title><meta name="generator" content="amaya 8.1a, see http://www.w3.org/Amaya/" />     6   <link href="styles.css" rel="stylesheet" type="text/css" /></head>     7 <body>     8 <h1>Creating Applications: Write a Web Resource</h1>     9 <p>With a completed template after the <a href="design.html">design</a>,    10 <a href="structure.html">structure annotation</a> and <a href="selectors.html">selector annotation</a>, we may now write a Web    11 resource which will expose our form as a Web application, allowing    12 users to input information and to manipulate that information using    13 their Web browser. Whilst XSLForms is just a normal Python package    14 which can be used from many kinds of programs and environments, we    15 shall concentrate on using the built-in <a href="http://www.boddie.org.uk/python/WebStack.html">WebStack</a>    16 support to build a    17 WebStack application around our form template.</p>    18 <h2>XSLForms Meets WebStack </h2>    19 <p>In the <a href="directory.html">directory structure</a> created    20 earlier, we now want to edit the&nbsp;<code>__init__.py</code> file and    21 add code which will do most of the work of the form-editing    22 application. Here is the start of this code:</p>    23 <pre>#!/usr/bin/env python<br /><br />"A very simple example application."<br /><br />import WebStack.Generic<br />import XSLForms.Resources.WebResources<br />import XSLForms.Utils<br />import os<br /><br /># Resource classes.<br /><br />class VerySimpleResource(XSLForms.Resources.WebResources.XSLFormsResource):<br /><br />    # To be continued.</pre>    24 <p>The above import statements just include in our application    25 everything that it is likely to need from WebStack, XSLForms and the    26 standard library. Then, we define a class inheriting from a special    27 XSLForms class which does some of the tedious Web application    28 housekeeping that we would otherwise need to do ourselves.</p>    29 <p>We may expand the above class definition as follows:</p>    30 <pre>class VerySimpleResource(XSLForms.Resources.WebResources.XSLFormsResource):<br /><br />    "A very simple resource providing a hierarchy of editable fields."<br /><br />    resource_dir = os.path.join(os.path.split(__file__)[0], "Resources")<br />    encoding = "utf-8"<br />    template_resources = {<br />        "structure" : ("structure_template.xhtml", "structure_output.xsl")<br />        }<br /><br />    def respond_to_form(self, trans, form):<br /><br />        """<br />        Respond to a request having the given transaction 'trans' and the given<br />        'form' information.<br />        """<br /><br />        # To be continued.</pre>    31 <p>The class is started with some attribute definitions:</p>    32 <ul>    33   <li>The&nbsp;<code>resource_dir</code> attribute is used to locate    34 the template, stylesheet and other non-Python resources. We calculate    35 this attribute by taking the location of the Python package itself and    36 finding the&nbsp;<code>Resources</code> subdirectory, just as described    37 in the <a href="directory.html">directory structure</a> document.</li>    38   <li>The&nbsp;<code>encoding</code> attribute is not strictly    39 necessary, but it states which character encoding will be used in the    40 Web pages generated by the template, and UTF-8 is a safe choice in most    41 situations.</li>    42   <li>The&nbsp;<code>template_resources</code> attribute is a    43 dictionary mapping a name onto details about our template and the    44 stylesheet that will actually produce the Web pages for each form being    45 edited.<br />    46     <ol>    47       <li>For the key, we choose a name that can easily be remembered    48 and associated with our template:&nbsp;<code>structure</code> (since    49 the root element of the form data is always&nbsp;<code>structure</code>)</li>    50       <li>Then, we specify the filename of our template in the&nbsp;<code>Resources</code>    51 directory:&nbsp;<code>structure_template.xhtml</code> (if the suggested    52 name was used)</li>    53       <li>Finally, we choose a filename for the stylesheet. Since this    54 is automatically produced from the template, we only need to choose a    55 name which is not already in use by another file, and for clarity a    56 name similar to that of the template is recommended:&nbsp;<code>structure_output.xsl</code></li>    57     </ol></li></ul>    58 <p>The class also has a method which resembles the typical&nbsp;<code>respond</code>    59 method of normal <a href="http://www.boddie.org.uk/python/WebStack.html">WebStack</a>    60 resources: the&nbsp;<code>respond_to_form</code> method is, in fact, a    61 special version of that method providing ready-to-use information about    62 the form (or forms) being edited.</p>    63 <p>We may now add to the above method definition by considering what    64 the resource needs to do when being sent a request by a user of the    65 application.</p>    66 <h3>Defining the Method</h3>    67 <p>First of all, we need to inspect the&nbsp;<code>form</code> object    68 to see if any form data is available. Since the data is provided    69 throughout XSLForms as XML documents, we call the&nbsp;<code>get_documents</code>    70 method on the&nbsp;<code>form</code> object:</p>    71 <pre>        documents = form.get_documents()</pre>    72 <p>As a result of this method, we should now have a dictionary mapping    73 form names to XML documents containing form data. However, it is not    74 guaranteed that the form data for our chosen form,&nbsp;<code>structure</code>,    75 even exists since a user may be visiting the resource for the first    76 time.</p>    77 <p>Therefore, we test to see if the&nbsp;<code>structure</code>    78 document exists, creating a new document if it did not:</p>    79 <pre>        # Ensure the presence of a document.<br /><br />        if documents.has_key("structure"):<br />            structure = documents["structure"]<br />        else:<br />            structure = form.new_instance("structure")<br /></pre>    80 <p>Now we should have a document containing the data for the form being    81 edited, regardless of whether any form was filled out and submitted or    82 whether we have created a new one for that purpose.</p>    83 <p>It may be the case that a user pressed a button in order to add or    84 remove items or subitems from the form. We must respond to such things    85 by examining the selector information to see which parts of the&nbsp;<code>structure</code>    86 document are affected:</p>    87 <pre>        # Add and remove elements according to the selectors found.<br /><br />        selectors = form.get_selectors()<br /></pre>    88 <p>The result of <code>get_selectors</code> is a dictionary mapping    89 selector names to lists of&nbsp;nodes affected by each particular    90 selector. In the <a href="selectors.html">selector annotation</a>    91 process, we defined selectors for the addition and removal of items and    92 subitems, and for convenience we pass the results for each selector to    93 a special function to perform the appropriate operation for us:</p>    94 <pre>        XSLForms.Utils.remove_elements(selectors.get("remove2"))<br />        XSLForms.Utils.add_elements(selectors.get("add2"), "subitem")<br />        XSLForms.Utils.remove_elements(selectors.get("remove"))<br />        XSLForms.Utils.add_elements(selectors.get("add"), "item")<br /></pre>    95 <p>Finally, we are ready to present the edited form data. In typical    96 WebStack fashion, we emit the content type of the final output along    97 with our chosen character encoding:</p>    98 <pre>        # Start the response.<br /><br />        trans.set_content_type(WebStack.Generic.ContentType("application/xhtml+xml", self.encoding))<br /></pre>    99 <p>Then, we ensure that our template is ready to use by calling the   100 superclass's&nbsp;<code>prepare_output</code> method with the name of   101 the form:</p>   102 <pre>        # Ensure that an output stylesheet exists.<br /><br />        trans_xsl = self.prepare_output("structure")<br /></pre>   103 <p>This prepares the stylesheet whose file is named in the&nbsp;<code>template_resources</code>   104 attribute entry, and this stylesheet is then sent to the   105 superclass's&nbsp;<code>send_output</code> method as part of a list of   106 stylesheets (although we only use a single stylesheet in this example)   107 along with the form data itself:</p>   108 <pre>        # Complete the response.<br /><br />        self.send_output(trans, [trans_xsl], structure)</pre>   109 <p>At this point, the user should receive their edited form and be able   110 to make more modifications.</p>   111 <h3>Deployment Details</h3>   112 <p>Some additional code is required to deploy this example application   113 using WebStack. We have chosen to expose the above resource class using   114 a special function which can be called from outside the package to   115 obtain an instance of the class:</p>   116 <pre># Site map initialisation.<br /><br />def get_site():<br /><br />    "Return a simple Web site resource."<br /><br />    return VerySimpleResource()</pre>   117 <p>To actually deploy the application, we could choose one of many   118 server environments supported by WebStack. For clarity, we choose here   119 to write the following separate program which we can save under the   120 name&nbsp;<code>VerySimpleApp.py</code> (for example):</p>   121 <pre>#!/usr/bin/env python<br /><br />from WebStack.Adapters.BaseHTTPRequestHandler import deploy<br />import VerySimple<br /><br /># Get a simple Web site.<br /><br />resource = VerySimple.get_site()<br /><br /># Special magic incantation.<br /><br />print "Serving..."<br />deploy(resource, handle_errors=0)</pre>   122 <p>Ensuring that the example application's package (which we   123 called&nbsp;<code>VerySimple</code> in the directory structure   124 document), WebStack, libxml2dom and XSLForms are available to the above   125 program, we may now run this program:</p>   126 <pre>python VerySimpleApp.py</pre>   127 <p>It should then be possible to visit the URL&nbsp;<code>http://localhost:8080/</code>   128 and edit the form in your Web browser.<br />   129 </p>   130 <h2>Further Enhancements</h2>   131 <p>We should now have an application which can be deployed and tested   132 using the usual WebStack techniques. However, more advanced templates   133 can be designed, and we shall consider <a href="multiple.html">multiple-choice   134 fields</a> in&nbsp;the next activity in the development <a href="overview.html">process</a>.</p>   135 </body></html>