Creating Applications: Write a Web Resource

With a completed template after the design, structure annotation and selector annotation, we may now write a Web resource which will expose our form as a Web application, allowing users to input information and to manipulate that information using their Web browser. Whilst XSLForms is just a normal Python package which can be used from many kinds of programs and environments, we shall concentrate on using the built-in WebStack support to build a WebStack application around our form template.

XSLForms Meets WebStack

In the directory structure created earlier, we now want to edit the __init__.py file and add code which will do most of the work of the form-editing application. Here is the start of this code:

#!/usr/bin/env python

"A very simple example application."

import WebStack.Generic
import XSLForms.Resources.WebResources
import XSLForms.Utils
import os

# Resource classes.

class VerySimpleResource(XSLForms.Resources.WebResources.XSLFormsResource):

# To be continued.

The above import statements just include in our application everything that it is likely to need from WebStack, XSLForms and the standard library. Then, we define a class inheriting from a special XSLForms class which does some of the tedious Web application housekeeping that we would otherwise need to do ourselves.

We may expand the above class definition as follows:

class VerySimpleResource(XSLForms.Resources.WebResources.XSLFormsResource):

"A very simple resource providing a hierarchy of editable fields."

resource_dir = os.path.join(os.path.split(__file__)[0], "Resources")
encoding = "utf-8"
template_resources = {
"structure" : ("structure_template.xhtml", "structure_output.xsl")
}

def respond_to_form(self, trans, form):

"""
Respond to a request having the given transaction 'trans' and the given
'form' information.
"""

# To be continued.

The class is started with some attribute definitions:

The class also has a method which resembles the typical respond method of normal WebStack resources: the respond_to_form method is, in fact, a special version of that method providing ready-to-use information about the form (or forms) being edited.

We may now add to the above method definition by considering what the resource needs to do when being sent a request by a user of the application.

Defining the Method

First of all, we need to inspect the form object to see if any form data is available. Since the data is provided throughout XSLForms as XML documents, we call the get_documents method on the form object:

        documents = form.get_documents()

As a result of this method, we should now have a dictionary mapping form names to XML documents containing form data. However, it is not guaranteed that the form data for our chosen form, structure, even exists since a user may be visiting the resource for the first time.

Therefore, we test to see if the structure document exists, creating a new document if it did not:

        # Ensure the presence of a document.

if documents.has_key("structure"):
structure = documents["structure"]
else:
structure = form.new_instance("structure")

Now we should have a document containing the data for the form being edited, regardless of whether any form was filled out and submitted or whether we have created a new one for that purpose.

It may be the case that a user pressed a button in order to add or remove items or subitems from the form. We must respond to such things by examining the selector information to see which parts of the structure document are affected:

        # Add and remove elements according to the selectors found.

selectors = form.get_selectors()

The result of get_selectors is a dictionary mapping selector names to lists of nodes affected by each particular selector. In the selector annotation process, we defined selectors for the addition and removal of items and subitems, and for convenience we pass the results for each selector to a special function to perform the appropriate operation for us:

        XSLForms.Utils.remove_elements(selectors.get("remove2"))
XSLForms.Utils.add_elements(selectors.get("add2"), "subitem")
XSLForms.Utils.remove_elements(selectors.get("remove"))
XSLForms.Utils.add_elements(selectors.get("add"), "item")

Finally, we are ready to present the edited form data. In typical WebStack fashion, we emit the content type of the final output along with our chosen character encoding:

        # Start the response.

trans.set_content_type(WebStack.Generic.ContentType("application/xhtml+xml", self.encoding))

Then, we ensure that our template is ready to use by calling the superclass's prepare_output method with the name of the form:

        # Ensure that an output stylesheet exists.

trans_xsl = self.prepare_output("structure")

This prepares the stylesheet whose file is named in the template_resources attribute entry, and this stylesheet is then sent to the superclass's send_output method as part of a list of stylesheets (although we only use a single stylesheet in this example) along with the form data itself:

        # Complete the response.

self.send_output(trans, [trans_xsl], structure)

At this point, the user should receive their edited form and be able to make more modifications.

Deployment Details

Some additional code is required to deploy this example application using WebStack. We have chosen to expose the above resource class using a special function which can be called from outside the package to obtain an instance of the class:

# Site map initialisation.

def get_site():

"Return a simple Web site resource."

return VerySimpleResource()

To actually deploy the application, we could choose one of many server environments supported by WebStack. For clarity, we choose here to write the following separate program which we can save under the name VerySimpleApp.py (for example):

#!/usr/bin/env python

from WebStack.Adapters.BaseHTTPRequestHandler import deploy
import VerySimple

# Get a simple Web site.

resource = VerySimple.get_site()

# Special magic incantation.

print "Serving..."
deploy(resource, handle_errors=0)

Ensuring that the example application's package (which we called VerySimple in the directory structure document), WebStack, libxml2dom and XSLForms are available to the above program, we may now run this program:

python VerySimpleApp.py

It should then be possible to visit the URL http://localhost:8080/ and edit the form in your Web browser.

Further Enhancements

We should now have an application which can be deployed and tested using the usual WebStack techniques. However, more advanced templates can be designed, and we shall consider multiple-choice fields in the next activity in the development process.