XQuery/Chaining Web Forms
Motivation
editYou want to create a series of web pages that pass information from one page to the next. This is very typical in web application development for example in the creation of "wizards" that ask the user for a series of questions on separate web pages.
Methods
editWe will use three methods to demonstrate this:
- on the client using URL parameters and hidden form fields
- on the client in cookies
- on the server using sessions
Using URL Parameters and Hidden Form Fields
editIn this method we will use a series of HTML forms in successive pages. Each page will gather some information and pass this information on the next form by adding additional parameters to the URL. We will use the request:get-parameter functions to get the key-value pairs from the URL.
Our first form will ask the user for their name. The second will ask them their favorite color.
Here is and example of the first form:
question-1.html
<html>
<head>
<title>Question 1: Your Name</title>
</head>
<body>
<h1>Question 1</h1>
<form action="question-2.xq">
<span class="label">Please enter your first name:</span>
<input type="text" name="name"/><br/>
<input type="submit" value="Next Question"/>
</form>
</body>
</html>
The URL is passed to the second form and we will use the request:get-parameter() function to get the value from the URL.
Here is the XQuery function for question 2. question-2.xq
xquery version "1.0";
declare option exist:serialize "method=xhtml media-type=text/html omit-xml-declaration=yes indent=yes";
let $name := request:get-parameter('name', '')
let $title := 'Question 2: Enter Your Favorite Color'
return
<html>
<head>
<title>{$title}</title>
</head>
<body>
<h1>{$title}</h1>
<form action="result.xq">
<span class="label">Hello {$name}. Please enter your favorite color:</span>
<input type="hidden" name="name" value="{$name}"/>
<input type="text" name="color"/><br/>
<input type="submit" value="Results"/>
</form>
</body>
</html>
Note that we are storing the incoming name in a hidden input field in the form. The value of the hidden field must take the value of the incoming {$name} parameter.
The last page just gets the two input parameters and displays them in an HTML page. If you look at the URL it will be of the format:
result.xq?name=dan&color=blue
result.xq
xquery version "1.0";
declare option exist:serialize "method=xhtml media-type=text/html omit-xml-declaration=yes indent=yes";
let $name := request:get-parameter('name', '')
let $color := request:get-parameter('color', '')
let $title := 'Result'
return
<html>
<head>
<title>{$title}</title>
</head>
<body>
<h1>{$title}</h1>
<p>Hello {$name}. Your favorite color is {$color}</p>
</body>
</html>
Discussion
editThis method is the preferred method since it does not require the client browser to support cookies. It also does not require the users to have a login a manage sessions. Sessions have the disadvantage that if the user gets interrupted half way through the process their session information will be lost and all the data they entered will need to be re-entered.
Note that although the first "name" parameter is not visible in the second form, the value is visible in the URL. So the term "hidden" does not apply to the URL, only the form.
Using Cookies
editIn this example we will use the following functions for setting and getting cookies:
response:set-cookie($name as xs:string, $value as xs:string) empty() request:get-cookie-value($cookie-name as xs:string) xs:string?
The first form is identical to the example above. But the
xquery version "1.0";
declare option exist:serialize "method=xhtml media-type=text/html omit-xml-declaration=yes indent=yes";
(: get the input and set the name cookie :)
let $name := request:get-parameter('name', '')
let $set-cookie := response:set-cookie('name', $name)
let $title := 'Question 2: Enter Your Favorite Color'
return
<html>
<head>
<title>{$title}</title>
</head>
<body>
<h1>{$title}</h1>
<form action="result.xq">
<span class="label">Hello {$name}. Please enter your favorite color:</span>
<input type="text" name="color"/><br/>
<input type="submit" value="Results"/>
</form>
</body>
</html>
Our first form will set the first cookie value and our second form will read the name cookie's value.
xquery version "1.0";
declare option exist:serialize "method=xhtml media-type=text/html omit-xml-declaration=yes indent=yes";
let $name := request:get-cookie-value('name')
let $color := request:get-parameter('color', '')
let $title := 'Result From Cookies'
return
<html>
<head>
<title>{$title}</title>
</head>
<body>
<h1>{$title}</h1>
<p>Hello {$name}. Your favorite color is {$color}</p>
</body>
</html>
Discussion
editUsing cookies can be complex and you must be very careful that your cookies are not changed by another application from the same domain. Your design must also consider the fact that browsers and users disable cookies.
Using Sessions
editThe last method is to use server session values to store the key-value data. This will be very similar to the last example but we will use the eXist Session module functions to set and get the values.
Here are the two calls we will need:
session:set-attribute($name as xs:string, $value as item()*) empty() session:get-attribute($name as xs:string) xs:string*
You only need to make a change to a single line of the 2nd form. Just change the lines to the following:
(: get the name and set the session :) let $name := request:get-parameter('name', ) let $set-session := session:set-attribute('name', $name)
and in the final result script just get the data from the session:
let $name := session:get-attribute('name')
Discussion
editUsing sessions can also be complex if you are new to session management. There are many rules that govern session timeouts and both the web server and database server may need to be configured to take your users needs into account. Session management may also not appropriate for public web sites that have policies against collection information on the web server.
Trade off Analysis
editThere are many points to consider. Storing information in URLs has many advantages since user can start a multi-step form and come back later to finish. As long as they do not shut down their browser the URL parameters will remain.
Cookies will remain on the client until the user takes some action to remove them. These are very useful when you do not want to have a person re-enter data for each session. Cookies tend to be ideal for storing users preferences when you do not have the ability to store them on the server.
Sessions are most useful when you have users authenticate with a login but data is lost when the users log out or their session times out.