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 <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 <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 <code>Resources</code> subdirectory, just as described 37 in the <a href="directory.html">directory structure</a> document.</li> 38 <li>The <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 <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: <code>structure</code> (since 49 the root element of the form data is always <code>structure</code>)</li> 50 <li>Then, we specify the filename of our template in the <code>Resources</code> 51 directory: <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: <code>structure_output.xsl</code></li> 57 </ol></li></ul> 58 <p>The class also has a method which resembles the typical <code>respond</code> 59 method of normal <a href="http://www.boddie.org.uk/python/WebStack.html">WebStack</a> 60 resources: the <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 <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 <code>get_documents</code> 70 method on the <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, <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 <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 <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 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 <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 <code>template_resources</code> 104 attribute entry, and this stylesheet is then sent to the 105 superclass's <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 <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 <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 <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 the next activity in the development <a href="overview.html">process</a>.</p> 135 </body></html>