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:
- XPE Forms validation is based on either W3C Schema or Relax NG Schema
- XPE Forms processing is handled by the XPE Forms formsServer
- Forms data - the data to fill in forms fields is defined in the forms instance and must conform to the declared schema
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:
<authentication>
<username>
fred
</username>
<password>
flintstone
</password>
</authentication>
</instance>
Validation
Validation of Forms data is usually performed in two steps:
- Field level validation
- 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:
- Maximum number of characters that can be entered.
- Wether the field is manatory or optional
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: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:
And define the XPE pipe in the xpipedef.xml file:
<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:
- images
- css files
- xsd files
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:
This outer element can have a number of attributes:
- debug="{true|false}" This attribute when set to true displays extra debuging information when form validation fails. It is usefull when developing applications, but should be set to false or removed prior to releasing an application.
- method="{GET|POST}" This attribute specifies the HTTP method to use when the form is submitted. (usually POST)
- action={"uri"} This attribute identifies the URI that accepts the the submission request once the form passes all schema based validation tests. The action pipeline can perform any business processing required and should then return either an indication of success, or one of failure.
- name="{name}" ????/
- onError="{uri}" This attribute identifies an optional URI that XPE forms will redirect to if the action uri returns an error condition. If ommited XPE forms will display an error form containing the error message returned by the action uri.
- onSuccess="{uri}" This attribute identifies the URI that XPE forms will redirect to if the action uri returns a success indication.
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:
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: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:
- name A name to identify the schema with.
- src A uri that points to the schema. This can be an internal (relative path) uri or an external uri. We are using an external uri (the same one that we used to test our access to the .xsd
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: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: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:
- Is required (mandatory) as specified by the required attribute.
- Is 20 characters in display width as specified by the width attribute.
- Only allows a maximum of 20 characters to be entered as specified by the maxlength attribute.
- Will have a label of Username as specified by the display attribute.
- Is a field type of input as specified by the ui attribute.
- Gets its value from and stores its value to authentication/username element of the instance data as specified by the ref attribute.
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: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:
- Take our http request and inject into the xml pipeline a request to include xinclude the contents of our logon.xml.
- Use the XPE xinclude filter to fetch and include the logon.xml file.
- Create a request to POST the contents of xml stream containing our form to the XPE form server.
- 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:
Now create the pipeline definition in the xpipedef.xml file:
<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:
<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: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:
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:http="http://www.xml.org/pipe/HTTP"
Now if you build and deploy the application and navigate to http://localhost:8188/xpe/tutorial/tut5/logon you should see something sililar to:
This is the request to include our form. Now we add the xinclude filter into our pipeline to actually fetch the file:
<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: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:
<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: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:
<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:
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:
<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:
<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:
The entire urlPattern file should look something like:
<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:
- XPE pipelines createing FORMS validating against an XSD schema
- XPE pipelines calling Restfull Web Services carrying out business functions - logon authentication
- XPE pipelines FORMS demonstrating simple navigation.
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.