Tutorial 5 - Creating a simple Form

Description

This tutorial will show you how to use XPE to generate XML based forms. It will be our longest tutorial so far as things begin to get slightly more complex. It is actually longer than it would be in real life since some of the steps we go through could be done more efficiently and are being presented as is to illustrate step by step how XPE pipelines operate in transforming XML.

We will create a simple logon form having a username and password field. We will then call a server side pipeline to process the request when the user presses the submit button.

Step 1 - Prerequisites

You will need both the XPE forms service and XPE Util module installed.

For instructions on how to install these modules refer to the XPE Installation Guide

Fundamental Concepts

To utilise XPE forms a number of fundamental concepts must be understood:

If you are familiar with W3C XForms, then you should not find XPE Forms concepts difficult at all, as they are very similar.

Step 2 - Instance Data and Validation

Instance Data

XPE Forms relies primarily on instance data (which is an xml fragment) to hold the data our forms need to display and capture. When a user submits the form, this instance data is sent to a Business Pipeline (any XPE pipeline) for processing.

The following XML fragment is an example of the instance data required by our form:

<instance  xmlns="http://www.xmlpipe.org/xpe/manual" >
   <authentication>
      <username>
         fred
      </username>
      <password>
         flintstone
      </password>
   </authentication>
</instance>

Validation

Validation of Forms data is usually performed in two steps:

  1. Field level validation
  2. Business Rules level validation

XPE Forms allows two methods (used individually or together) to be used to perform Field level validation of the instance data.

Firstly, the form field definitions can declare certain constraints, such as:

Secondly, XPE Forms allows us to declare either a W3C Schema, or a Relax NG schema against which the instance data should be vailidate against. In this tutorial we will specify both form field validation and W3C Schema validation.

Business Rules validation is usually performed within the pipeline the instance data is sent to when a form is submitted. This business pipeline can then return an error if the business level validations fail. This error can be displayed to the user by XPE Forms, which then allows the user to go back and re-enter the forms data and resubmit the form.

Lets now create our W3C Schema that we will use to validate our instance data. Create a file containing this schema and save it as authentication.xsd in the direcory: ROOT/tutorial/xsd

<xs:schema  xmlns:xs="http://www.w3.org/2001/XMLSchema" >
   <xs:element  name="authentication" >
      <xs:complexType>
         <xs:sequence>
            <xs:element  ref="username" />
            <xs:element  ref="password" />
         </xs:sequence>
      </xs:complexType>
   </xs:element>
   <xs:element  name="username" >
      <xs:simpleType>
         <xs:restriction  base="xs:string" >
            <xs:minLength  value="1" />
            <xs:maxLength  value="50" />
         </xs:restriction>
      </xs:simpleType>
   </xs:element>
   <xs:element  name="password" >
      <xs:simpleType>
         <xs:restriction  base="xs:string" >
            <xs:minLength  value="5" />
            <xs:maxLength  value="20" />
         </xs:restriction>
      </xs:simpleType>
   </xs:element>
</xs:schema>

Step 3 - Accessing the schema

Before proceeding to the form itself, we need to make the authentication schema accessible. There are a number of ways to do this. We will choose to make the schema available via an XPE pipeline. This way we can publish the schema and look at it via a browser.

To do this we define a new XPE pattern in our urlPattern.xml file within the GET method element:

<map  pattern="/tutorial/xsd/*"  xpipe="http://www.xml.org/pipe/xpe/tutorial/binary"  xmlns="http://www.xml.org/xml/pipe" />

And define the XPE pipe in the xpipedef.xml file:

<register  uri="binary"  xmlns="http://www.xml.org/xml/pipe" >
   <xpipe>
      <xnode  type="http://www.xml.org/pipe/xpe/source/http" />
      <xnode  type="http://www.xml.org/pipe/xpe/pub/request2binInclude" />
      <xnode  type="http://www.xml.org/pipe/xpe/filter/resolver" />
      <xsink  type="http://www.xml.org/pipe/xpe/sink/http/bin" >
         <property  name="Cache-Control"  value="max-age=30000" />
      </xsink>
   </xpipe>
</register>

Don't worry too much about the details of this pipe. It is a standard pattern that is used in most applications to access many types of files such as:

Now build and deploy the application. In a browser, go to the uri http://localhost:8188/xpe/tutorial/xsd/authentication.xsd. Depending on your browser, you should either have the schema displayed, or an option to download it. In either case this demonstrates that the schema is accessible. If you don't see this behaviour, check the urlPattern to ensure it is correct, and make sure the file was created in the correct directory. Also check that the build was successfull and the deployment was also successfull.

Step 4 - Creating the form

XPE Forms is a sophisticated package containing many advanced features. In this tutorial we will demonstrate just a number of basic features. For further details about the advanced features refer to the online XPE documantation (http://softtouchit.com/xpe/manual/xpeForm)

Our form will simply have two input fields allowing you to enter a username and password and will attempt to validate the username/password using our authentication pipeline from tutorial 3.

Now lets create our form piece by piece. The first point to note is that we will be creating our form in a static xml file. This is quite ok and just like any xml that participates in an XPE pipeline we could use xslt to modify and manipulate it prior to displaying the form to the user. In a real application the entire form could be created via xslt. But for this tutorial we are going to keep it simple to illustrate the construction and concepts involved in XPE forms generation.

Form element

Our first task is to construct the form element itself. Create a file called logon.xml in the ROOT/tutorial/forms directory and enter the following line:

<xf:form  debug="true"  method="POST"  action=" http://localhost:8188/xpe/tutorial/tut3/dbauthenticate"  name="logon"  onSuccess="http://localhost:8188/xpe/tutorial/html/logonsuccess.html"  xmlns:xf="http://www.xmlpipe.org/xpe/form" />

This outer element can have a number of attributes:

Simply create an xml file with the xf:form element as it appears above and save it as ROOT/tutorial/forms/logon.xml.

Now we need to create the urlPattern entry that allows access to these files:

<map  pattern="/tutorial/forms/*"  xpipe="http://www.xml.org/pipe/xpe/tutorial/binary"  xmlns="http://www.xml.org/xml/pipe" />

As you can see, in this example we will be using the binary pipeline that we used for the .xsd file.

Before going any further lets try and retieve the one line forms definition. Build and deploy the tutorials, then using a browser type in the url: http://localhost:8188/xpe/tutorial/forms/logon.xml

The raw forms xml should be displayed. If it isn't, check to ensure that the build and deployement didn't generate any errors. Check also the urlPattern entry.

Schema Declaration

Next we will add the schema declaration that will provide our basic field level validation. Edit the logon.xml file to look something like:

<xf:form  debug="true"  method="POST"  action=" http://localhost:8188/xpe/tutorial/tut3/dbauthenticate"  name="logon"  onSuccess="http://localhost:8188/xpe/tutorial/html/logonsuccess.html"  xmlns:xf="http://www.xmlpipe.org/xpe/form" >
   <xf:schema  name="http://example.com/authentication.xsd"  src="http://localhost:8188/xpe/tutorial/xsd/authentication.xsd" />
</xf:form>

Here we just create a xf:schema entry and provide the following attributes:

Instance Element

XPE Forms uses what is termed the form instance to hold the data that is to be displayed by the form. It is this filled in instance element that once validated is submitted to the business pipeline. This element must conform to the schema that is used to validate the form.

<xf:form  debug="true"  method="POST"  action="http://localhost:8188/xpe/tutorial/tut3/dbauthenticate"  name="logon"  onSuccess="http://localhost:8188/xpe/tutorial/html/logonsuccess.html"  xmlns:xf="http://www.xmlpipe.org/xpe/form" >
   <xf:schema  name="http://example.com/authentication.xsd"  src="http://localhost:8188/xpe/tutorial/xsd/authentication.xsd" />
   <xf:instance  schema="http://example.com/authentication.xsd" >
      <authentication  xmlns="" >
         <username/>
         <password/>
      </authentication>
   </xf:instance>
</xf:form>

As you can see we have create the xf:instance element and specified which schema to use via the schema attribute.

Form fields

Finally we are ready to define the form fields. We will group our two fields together in a xf:group element:

<xf:form  debug="true"  method="POST"  action="http://localhost:8188/xpe/tutorial/tut3/dbauthenticate"  name="logon"  onSuccess="http://localhost:8188/xpe/tutorial/html/logonsuccess.html"  xmlns:xf="http://www.xmlpipe.org/xpe/form" >
   <xf:schema  name="http://example.com/authentication.xsd"  src="http://localhost:8188/xpe/tutorial/xsd/authentication.xsd" />
   <xf:instance  schema="http://example.com/authentication.xsd" >
      <authentication  xmlns="" >
         <username/>
         <password/>
      </authentication>
   </xf:instance>
   <xf:group  nodeset="authentication"  display="Authentication" >
      <xf:field  required="yes"  size="20"  maxlength="50"  ui="input"  ref="authentication/username"  display="Username" >
         <xf:hint>
            upto 20 characters
         </xf:hint>
         <xf:help>
            Please enter your registered username. (upto 50 alphanumeric characters)
         </xf:help>
      </xf:field>
      <xf:field  required="yes"  size="20"  maxlength="20"  ui="password"  ref="authentication/password"  display="Password" >
         <xf:hint>
            5 to 20 alphanumeric characters
         </xf:hint>
         <xf:help>
            Please enter your password (5 to 20 alphanumeric characters).
         </xf:help>
      </xf:field>
   </xf:group>
</xf:form>

The xf:group element will group our two fields together and by default place a border around the two fields. The display attribute provides a label for the group. The nodeset attribute identifies a set of nodes within the instance data. This can then be used to provide shortcut reference naming within the xf:field elements. The nodeset is more relevant when used in conjunction with repeating elements and fields. (Refer to the online XPE Forms manual for further details).

Next we define our username field. This field:

The xf:hint and xf:help elements allow float over hints and help text to be associated with the form fields. The xf:hint text will display as float-over text when the cursor pointer (mouse pointer) is placed over the input field. The xf:help text is displayed as float-over text when the pointer is placed over the field label.

The Password field is very similar with the main difference being the ui attribute set to password.

All that is left now is to add the submit button:

<xf:form  debug="true"  method="POST"  action="http://localhost:8188/xpe/tutorial/tut3/dbauthenticate"  name="logon"  onSuccess="http://localhost:8188/xpe/tutorial/html/logonsuccess.html"  xmlns:xf="http://www.xmlpipe.org/xpe/form" >
   <xf:schema  name="http://example.com/authentication.xsd"  src="http://localhost:8188/xpe/tutorial/xsd/authentication.xsd" />
   <xf:instance  schema="http://example.com/authentication.xsd" >
      <authentication  xmlns="" >
         <username/>
         <password/>
      </authentication>
   </xf:instance>
   <xf:group  nodeset="authentication"  display="Authentication" >
      <xf:field  required="yes"  size="20"  maxlength="50"  ui="input"  ref="authentication/username"  display="Username" >
         <xf:hint>
            upto 20 characters
         </xf:hint>
         <xf:help>
            Please enter your registered username. (upto 50 alphanumeric characters)
         </xf:help>
      </xf:field>
      <xf:field  required="yes"  size="20"  maxlength="20"  ui="password"  ref="authentication/password"  display="Password" >
         <xf:hint>
            5 to 20 alphanumeric characters
         </xf:hint>
         <xf:help>
            Please enter your password (5 to 20 alphanumeric characters).
         </xf:help>
      </xf:field>
   </xf:group>
   <xf:submit  display="Logon"  withReset="yes" />
</xf:form>

The Submit element will create a button labeled Logon as specified by the display attribute. The withReset attribute (if set to yes) will create a second button allowing the form field values to be reset to their original values.

Thats it, the form is ready to be displayed.

The Forms Service

XPE Forms uses an SOA (Service Oriented Architecture) approach to handling forms. To display the form, the form XML data must be POSTed to the formsService. If you have deployed the forms service on a particuler server, then it should be available at the uri: http://{servername}:{port}/xpe/formServer/html

If you are running the form server on the same server as the tutorials and it is the local machine then the uri would be: http://localhost:8188/xpe/formServer/html

This server performs many tasks, the main one we are currently interested in is to create the form. So we will post our xml data to: http://localhost:8188/xpe/formServer/html/create

To do this we will create a simple XPE pipeline that fetches the Form XML from our static file (ROOT/tutorial/forms/logon.xml) and POSTs it to the Forms Service. This pipeline will perform four functions:

  1. Take our http request and inject into the xml pipeline a request to include xinclude the contents of our logon.xml.
  2. Use the XPE xinclude filter to fetch and include the logon.xml file.
  3. Create a request to POST the contents of xml stream containing our form to the XPE form server.
  4. Use the XPE xinclude filter to post the requested XML to the forms server.

We will perform these tasks one step at a time so that you can see, appreciate and understand how the pipeline works.

Step 5 - Define our uri

First of all we need to define the urlPattern:

<map  pattern="/tutorial/tut5/logon"  xpipe="http://www.xml.org/pipe/xpe/tutorial/tut5/logon"  xmlns="http://www.xml.org/xml/pipe" />

Now create the pipeline definition in the xpipedef.xml file:

<xpipeDef  xmlns="http://www.xml.org/xml/pipe" >
   <register  uri="tut5/logon" >
      <xpipe>
         <xnode  type="http://www.xml.org/pipe/xpe/source/http" />
         <xsink  type="http://www.xml.org/pipe/xpe/sink/http" >
            <property  name="method"  value="xml" />
         </xsink>
      </xpipe>
   </register>
</xpipeDef>

If you build and deploy the application, you should be able to navigate to: http://localhost:8188/xpe/tutorial/tut5/logon and see your request echoed back.

Step 6 - Include our form into our pipeline.

Now lets add our first transformation that creates a request to fetch our form from the static logon.xml file:

<xpipeDef  xmlns="http://www.xml.org/xml/pipe" >
   <register  uri="xslt/form" >
      <xslt  href="ROOT/tutorial/xslt/form.xsl" />
   </register>
   <register  uri="tut5/logon" >
      <xpipe>
         <xnode  type="http://www.xml.org/pipe/xpe/source/http" />
         <xnode  type="xslt/form" />
         <xsink  type="http://www.xml.org/pipe/xpe/sink/http" >
            <property  name="method"  value="xml" />
         </xsink>
      </xpipe>
   </register>
</xpipeDef>

We need to create the file ROOT/tutorial/xslt/form.xsl:

<xsl:stylesheet  version="2.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
   <xsl:output  method="xml" />
   <xsl:template  match="http:httpRequest" >
      <xi:include  href="http://localhost:8188/xpe/tutorial/forms/logon.xml"  method="GET"  xmlns:xi="http://www.w3.org/2001/XInclude" />
   </xsl:template>
</xsl:stylesheet>

Note

Again, please ensure that the stylesheet above declares the namespaces:

in the xsl:stylesheet element. The above is slightly incorrect due to the prementioned documentation formatting bug.

Now if you build and deploy the application and navigate to http://localhost:8188/xpe/tutorial/tut5/logon you should see something sililar to:

<xi:include  href="http://localhost:8188/xpe/tutorial/forms/logon.xml"  method="GET"  xmlns:xi="http://www.w3.org/2001/XInclude" />

This is the request to include our form. Now we add the xinclude filter into our pipeline to actually fetch the file:

<register  uri="tut5/logon"  xmlns="http://www.xml.org/xml/pipe" >
   <xpipe>
      <xnode  type="http://www.xml.org/pipe/xpe/source/http" />
      <xnode  type="xslt/form" />
      <xnode  type="http://www.xmlpipe.org/xpe/filter/include" />
      <xsink  type="http://www.xml.org/pipe/xpe/sink/http" >
         <property  name="method"  value="xml" />
      </xsink>
   </xpipe>
</register>

Build and deploy the application, then navigate to http://localhost:8188/xpe/tutorial/tut5/logon. You should now see a copy of our form xml:

Step 7 - Post our form to the Form Server

Next we build the request to post this form to the form server. For this we create the xslt file ROOT/tutorial/xslt/formPost.xsl:

<xsl:stylesheet  version="2.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
   <xsl:output  method="xml" />
   <xsl:template  match="/" >
      <xi:include  href="http://localhost:8188/xpe/formServer/html/create"  method="POST"  xmlns:xi="http://www.w3.org/2001/XInclude" >
         <xi:content>
            <xsl:copy-of  select="."  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" />
         </xi:content>
      </xi:include>
   </xsl:template>
</xsl:stylesheet>

The pipeline needs to be altered to call this xslt:

<xpipeDef  xmlns="http://www.xml.org/xml/pipe" >
   <register  uri="xslt/form" >
      <xslt  href="ROOT/tutorial/xslt/form.xsl" />
   </register>
   <register  uri="xslt/formPost" >
      <xslt  href="ROOT/tutorial/xslt/formPost.xsl" />
   </register>
   <register  uri="tut5/logon" >
      <xpipe>
         <xnode  type="http://www.xml.org/pipe/xpe/source/http" />
         <xnode  type="xslt/form" />
         <xnode  type="http://www.xmlpipe.org/xpe/filter/include" />
         <xnode  type="xslt/formPost" />
         <xsink  type="http://www.xml.org/pipe/xpe/sink/http" >
            <property  name="method"  value="xml" />
         </xsink>
      </xpipe>
   </register>
</xpipeDef>

Build and deploy the application again. Now when you navigate to our url, you should see something similar to:

<xi:include  href="http://localhost:8188/xpe/formServer/html/create"  method="POST"  xmlns:xi="http://www.w3.org/2001/XInclude" >
   <xi:content>
      <xf:form  debug="true"  method="POST"  action=" http://localhost:8188/xpe/tutorial/tut3/dbauthenticate"  name="logon"  onSuccess="http://localhost:8188/xpe/tutorial/html/logonsuccess.html"  xmlns:xf="http://www.xmlpipe.org/xpe/form" >
         <xf:schema  name="http://example.com/authentication.xsd"  src="http://localhost:8188/xpe/tutorial/xsd/authentication.xsd" />
         <xf:instance  schema="http://example.com/authentication.xsd" >
            <authentication  xmlns="" >
               <username/>
               <password/>
            </authentication>
         </xf:instance>
         <xf:group  nodeset="authentication"  display="Authentication" >
            <xf:field  required="yes"  size="20"  maxlength="50"  ui="input"  ref="authentication/username"  display="Username" >
               <xf:hint>
                  upto 20 characters
               </xf:hint>
               <xf:help>
                  Please enter your registered username. (upto 50 alphanumeric characters)
               </xf:help>
            </xf:field>
            <xf:field  required="yes"  size="20"  maxlength="20"  ui="password"  ref="authentication/password"  display="Password" >
               <xf:hint>
                  5 to 20 alphanumeric characters
               </xf:hint>
               <xf:help>
                  Please enter your password (5 to 20 alphanumeric characters).
               </xf:help>
            </xf:field>
         </xf:group>
         <xf:submit  display="Logon"  withReset="yes" />
      </xf:form>
   </xi:content>
</xi:include>

You can see that we have built a request to POST our form to the form server using the XPE xi:include element.

Now we simply add the XInclude filter to the pipeline:

<register  uri="tut5/logon"  xmlns="http://www.xml.org/xml/pipe" >
   <xpipe>
      <xnode  type="http://www.xml.org/pipe/xpe/source/http" />
      <xnode  type="xslt/form" />
      <xnode  type="http://www.xmlpipe.org/xpe/filter/include" />
      <xnode  type="xslt/formPost" />
      <xnode  type="http://www.xmlpipe.org/xpe/filter/include" />
      <xsink  type="http://www.xml.org/pipe/xpe/sink/http" >
         <property  name="method"  value="xml" />
      </xsink>
   </xpipe>
</register>

Build and deploy the application again. Now when you navigate to our url, you should see something similar to:

<h:redirect  to="/xpe/formServer?xpf_form_id=xpf_b9081b22-10ae-1000-8126-f90c56dff14"  xmlns:h="http://www.xml.org/pipe/HTTP" />

This is the response from the form server. It is actually a redirect request to the form server internal representation of our form. The reason we are seeing this instead of the form is because our pipeline sink is an XML sink. Our final step is to turn our XML sink to a HTTP sink:

<register  uri="tut5/logon"  xmlns="http://www.xml.org/xml/pipe" >
   <xpipe>
      <xnode  type="http://www.xml.org/pipe/xpe/source/http" />
      <xnode  type="xslt/form" />
      <xnode  type="http://www.xmlpipe.org/xpe/filter/include" />
      <xnode  type="xslt/formPost" />
      <xnode  type="http://www.xmlpipe.org/xpe/filter/include" />
      <xsink  type="http://www.xml.org/pipe/xpe/sink/http" >
         <property  name="method"  value="html" />
      </xsink>
   </xpipe>
</register>

Build and deploy the application again (last time). Now when you navigate to our url, you should see our form:

Step 8 - Testing our form

Move the cursor over the username and password labels and fields. You should see our hint and help options:

Enter an invalid username and/or password (eg 'barney' 'rubble') XPE should execute the business pipeline (http://localhost:8188/xpe/tutorial/tut3/dbauthenticate) which should return an error that XPE forms will display:

You may then return to the form via the supplied url and try again. If you enter a valid username/password (fred/flintstone) then the business pipeline should return a successful result. In this case you should see the following error:

This is due to the fact that we have specified a onSuccess uri that does not exist. As the last step in this tutorial we will create this as a simple static html pipeline.

Step 9 - Creating the onSuccess pipeline

For simplicity our onSuccess pipeline will be a simple static html form. This is just to demonstrate the navigational aspects of XPE forms. Remember that the onSuccess pipeline could refer to any XPE pipeline (such as another form)

Create a simple html file:

<html  xmlns="http://www.w3.org/1999/xhtml" >
   <head>
      <meta  http-equiv="Content-Language"  content="en-us" />
      <title>
         XPE Tutorial 5
      </title>
   </head>
   <H2>
      Logon Successful
   </H2>
   <p>
      Congratulations.
   </p>
</html>

Save this file as ROOT/tutorial/html/logonsuccess.html.

Now add the following url pattern in the urlPattern.xml file under the GET method:

<map  pattern="/tutorial/html/*"  xpipe="http://www.xml.org/pipe/xpe/tutorial/binary"  xmlns="http://www.xml.org/xml/pipe" />

The entire urlPattern file should look something like:

<urlPattern  xmlns="http://www.xml.org/xml/pipe" >
   <method  name="GET" >
      <map  pattern="/tutorial/tut1/echo"  xpipe="http://www.xml.org/pipe/xpe/tutorial/tut1/echo" />
      <map  pattern="/tutorial/tut2/authenticate"  xpipe="http://www.xml.org/pipe/xpe/tutorial/tut2/authenticate" />
      <map  pattern="/tutorial/tut3/dbauthenticate"  xpipe="http://www.xml.org/pipe/xpe/tutorial/tut3/dbauthenticate" />
      <map  pattern="/tutorial/tut4/logon"  xpipe="http://www.xml.org/pipe/xpe/tutorial/tut4/logon" />
      <map  pattern="/tutorial/tut4/logonsuccess"  xpipe="http://www.xml.org/pipe/xpe/tutorial/tut4/logonsuccess" />
      <map  pattern="/tutorial/xsd/*"  xpipe="http://www.xml.org/pipe/xpe/tutorial/binary" />
      <map  pattern="/tutorial/forms/*"  xpipe="http://www.xml.org/pipe/xpe/tutorial/binary" />
      <map  pattern="/tutorial/html/*"  xpipe="http://www.xml.org/pipe/xpe/tutorial/binary" />
   </method>
   <method  name="POST" >
      <map  pattern="/tutorial/tut3/dbauthenticate"  xpipe="http://www.xml.org/pipe/xpe/tutorial/tut3/dbauthenticate" />
   </method>
</urlPattern>

Now rebuild and deploy the application. Try loging on with a valid username/password. If all is ok, you should now see a correct final page:

Summary

If this all works, then congratulations. You have build a mini application that includes:

Any Problems?

If you have problems getting this tutorial to work look at the completed solution in the tutorials/solutions/tutorial5 directory It should have all files required to buld and run the tutorial.