XSLTools

docs/Web-resource.html

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