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 <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 <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 <code>Resources</code> subdirectory, just as described 42 in the <a href="directory.html">directory structure</a> document.</li> 43 <li>The <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 <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: <code>structure</code> (since 54 the root element of the form data is always <code>structure</code>)</li> 55 <li>Then, we specify the filename of our template in the <code>Resources</code> 56 directory: <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: <code>structure_output.xsl</code></li> 62 </ol> 63 </li> 64 </ul> 65 <p>The class also has a method which resembles the typical <code>respond</code> 66 method of normal <a 67 href="http://www.boddie.org.uk/python/WebStack.html">WebStack</a> 68 resources: the <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 <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 <code>get_documents</code> 78 method on the <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, <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 <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 <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 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 <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 <code>template_resources</code> 112 attribute entry, and this stylesheet is then sent to the 113 superclass's <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 <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 <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 <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 the next activity in the development <a 143 href="overview.html">process</a>.</p> 144 </body> 145 </html>