<?xml version="1.0" encoding="UTF-8"?>
<!-- $Id: urlrewrite.xml 17299 2012-10-10 23:47:33Z joewiz $ --><book><bookinfo><productname>eXist-db – Open Source Native XML Database</productname><title>URL Rewriting and MVC Framework</title><orgname>The eXist-db Project</orgname><date>August 2012</date><author><firstname>Wolfgang</firstname><surname>Meier</surname></author></bookinfo><chapter><title>URL Rewriting and MVC Framework</title><abstract><para>Since version 1.3/1.4, eXist-db provides a simple, yet powerful module for URL
                rewriting and redirection: XQueryURLRewrite. It also incorporates a basic MVC (Model
                View Controller) framework, offering servlet-based pipeline processing. The module
                was in part inspired by the existing Open Source packages UrlRewriteFilter and
                Spring MVC. The main difference is that we are not using any configuration files to
                configure the URL rewriting. XQueryURLRewrite is based on XQuery instead.</para></abstract><section><title>Basics</title><para>XQueryURLRewrite is a standard Java servlet filter. Like any other servlet filter,
                it is configured in <filename>webapp/WEB-INF/web.xml</filename>. Its main job is to
                intercept incoming requests and forward them to the appropriate handlers, which are
                again standard servlets. In fact, there's nothing eXist-specific to the servlet
                filter, except that it uses XQuery scripts to configure the forwarding and URL
                rewriting.</para><para>A controller XQuery is executed once for every requests. It should return an XML
                fragment, which tells the servlet filter how to proceed with the request. The
                returned XML fragment may just define a simple forwarding, or it could describe
                complex pipelines involving multiple steps.</para><para>The main advantage of using XQuery for the controller is that we have the whole
                power of the language available for the URL rewriting. The controller can look at
                request parameters or headers, add new parameters or attributes, rewrite the request
                URI or access the database. There's basically no limit.</para></section><section><title>URL Rewriting</title><para>When designing RESTful web applications, a common rule is to provide meaningful
                URIs to the user. For example, our eXist wiki implements a hierarchical document
                space. The user can directly browse to a document by entering the path to it into
                the browser's location bar. The URL <ulink url="http://atomic.exist-db.org/HowTo/OxygenXML/">http://atomic.exist-db.org/HowTo/OxygenXML/eXistXmlRpcChanged</ulink> will
                directly lead to the corresponding document.</para><para>Internally, however, all document views are handled by the same XQuery script.
                Above URL will actually be forwarded to an XQuery called <filename>index.xql</filename> as follows:</para><synopsis>index.xql?feed=HowTo/OxygenXML/&amp;ref=eXistXmlRpcChanged</synopsis><para>The XQuery code which does the rewrite magic is shown below:</para><programlisting language="xquery">
let $params := subsequence(text:groups($exist:path, '^/?(.*)/([^/]+)$'), 2)
return
    &lt;dispatch xmlns="http://exist.sourceforge.net/NS/exist"&gt;
        &lt;forward url="/index.xql"&gt;
            &lt;add-parameter name="feed" value="{$params[1]}"/&gt;
            &lt;add-parameter name="ref" value="{$params[2]}"/&gt;
        &lt;/forward&gt;
    &lt;/dispatch&gt;</programlisting><para>The forward element tells XQueryURLRewrite to pass the request to the specified
                URL. You could also forward to a servlet instead of an URL by specifying its name
                (servlet="ServletName"). The forwarding is done via the
                    <classname>RequestDispatcher</classname> of the servlet engine and is thus
                invisible to the user. </para><para>Relative URLs within forward or redirect elements are interpreted relative to the
                request URI, absolute paths relative to the root of the current controller
                hierarchy. If the controller which processes the request is stored in the db, all
                absolute and relative paths will be resolved against the db as well. This is
                explained in more detail below.</para><para>If you want the user to see the rewritten URL, you can replace the
                    <sgmltag>forward</sgmltag> action with a <sgmltag>redirect</sgmltag>. A common
                use for <sgmltag>redirect</sgmltag> is to send the user to a default page:</para><programlisting language="xquery">if ($exist:path eq '/') then
    &lt;dispatch xmlns="http://exist.sourceforge.net/NS/exist"&gt;
    	&lt;redirect url="index.xml"/&gt;
    &lt;/dispatch&gt;</programlisting><para>If no action is specified within the dispatch element, the request will just be
                passed through the filter chain and will be handled the normal way. The same happens
                if the action is an element <sgmltag>ignore</sgmltag>. For example, the simplest
                controller script would consist of a single ignore:</para><programlisting language="xml">
        &lt;ignore xmlns="http://exist.sourceforge.net/NS/exist"&gt;
            &lt;cache-control cache="yes"/&gt;
        &lt;/ignore&gt;</programlisting><para>Most scripts in eXist-db return this if no other rule applies to a request.</para><note><para>It is important to understand that only one (!) controller will ever be
                    applied to a given request. It is not possible to forward from one controller to
                    another (or the same). Once you either ignored or forwarded a request in the
                    controller, it will be directly passed to the servlet which handles it or - if
                    it references a resource - it will be processed by the servlet engine itself.
                    The controller will not be called again for the same request.</para><para>Redirects are different in this respect: they cause the client (the web
                    browser) to send a second request and this will again be filtered by
                    XQueryURLRewrite. It is thus possible to create redirect loops.</para></note></section><section><title>Variables</title><para>Within a controller.xql file, you have access to the entire XQuery function
                library, including the functions in the request, response and session modules. You
                could thus use a function like <command>request:get-uri()</command> to get the
                current URI of the request. However, to simplify things, XQueryURLRewrite passes a
                few variables to the controller script:</para><variablelist><varlistentry><term>exist:path</term><listitem><para>The last part of the request URI after the section leading to the
                            controller. If the resource <filename>example.xml</filename> resides
                            within the same directory as the controller query,
                                <option>$exist:path</option> will be <filename>/example.xml</filename>.</para></listitem></varlistentry><varlistentry><term>exist:resource</term><listitem><para>The section of the URI after the last <filename>/</filename>, usually
                            pointing to a resource, e.g. <filename>example.xml</filename>.</para></listitem></varlistentry><varlistentry><term>exist:controller</term><listitem><para>The part of the URI leading to the current controller script. For
                            example, if the request path is <filename>/xquery/test.xql</filename>
                            and the controller is in the <filename>xquery</filename> directory,
                                <option>$exist:controller</option> would contain <filename>/xquery</filename>.</para></listitem></varlistentry><varlistentry><term>exist:prefix</term><listitem><para>If the current controller hierarchy is mapped to a certain path
                            prefix, <option>$exist:prefix</option> returns that prefix. For example,
                            the default configuration maps the path <filename>/tools</filename> to a
                            collection in the database (see below). In this case,
                                <option>$exist:prefix</option> would contain <filename>/tools</filename>.</para></listitem></varlistentry><varlistentry><term>exist:root</term><listitem><para>The root of the current controller hierarchy. This may either point to
                            the file system or to a collection in the database. Use this variable to
                            locate resources relative to the root of the application. For example,
                            assume you want to process a request through stylesheet <filename>db2xhtml.xsl</filename>, which could <emphasis>either</emphasis> be
                            stored in the <filename>/stylesheets</filename> directory in the root of
                            the webapp or - if the app is running from within the db - the
                            corresponding <filename>/stylesheets</filename> collection. You want
                            your app to be able to run from either location. The solution is to use
                                <option>exist:root</option>:</para><synopsis language="xml">&lt;forward servlet="XSLTServlet"&gt;
    &lt;set-attribute name="xslt.stylesheet"
    	value="{$exist:root}/stylesheets/db2xhtml.xsl"/&gt;
&lt;/forward&gt;</synopsis></listitem></varlistentry></variablelist><para>To summarize: if the request path is <filename>/exist/tools/sandbox/get-examples.xql</filename>,
                    <option>$exist:prefix</option> would contain <filename>/tools</filename>,
                    <option>$exist:controller</option> would point to <filename>/sandbox</filename>,
                    <option>$exist:path</option> would be <filename>/get-examples.xql</filename>,
                and <option>$exist:resource</option>: <filename>get-examples.xml</filename>.</para><para>You do not need to explicitly declare the variables or the namespace. However, if
                you would like to do so, you can add an external declaration for each used variable
                at the top of your XQuery as follows:</para><synopsis language="xquery">declare variable $exist:path as external;</synopsis></section><section><title>Locating Controller Scripts and Configuring Base Mappings</title><para>By convention, the controller XQueries should be called <filename>controller.xql</filename>. XQueryURLRewrite will try to guess the path to the
                most-specific controller query by looking at the request path. For example, in the
                standard eXist distribution, the main controller file is located in <filename>webapp/controller.xql</filename>, but there are other controllers in the
                subdirectories <filename>webapp/sandbox</filename> or <filename>webapp/admin</filename>. If the servlet filter receives a request path
                    <uri>http://localhost:8080/exist/sandbox/</uri>, it will find the <filename>controller.xql</filename> file in the <filename>sandbox</filename> directory
                and execute this controller instead of the main controller.</para><para>It is also possible to store the controller XQuery into the database instead of
                the file system. This makes sense if you want to keep a part of your web application
                within the db (which is a common approach).</para><para>In fact, one web application may have more than one controller hierarchy. For
                example, you may want to keep the main webapp within the file system, while some
                tools and scripts should be served from a database collection. This can be done by
                configuring two roots within the <filename>controller-config.xml</filename> file in
                    <filename>webapp/WEB-INF</filename>. <filename>controller-config.xml</filename>
                defines the base mappings used by XQueryURLRewrite. </para><para>It basically has two components:</para><itemizedlist><listitem><para><sgmltag>forward</sgmltag> actions which map patterns to servlets</para></listitem><listitem><para><sgmltag>root</sgmltag> elements define the root for a file system or db
                        collection hierarchy </para></listitem></itemizedlist><para>The <sgmltag>forward</sgmltag> tags specify path mappings for common servlets,
                similar to a servlet mapping in <filename>web.xml</filename>. The advantage is that
                XQueryURLRewrite becomes a single point of entry for the entire web application and
                we don't need to handle any of the servlet paths in the main controller. For
                example, if we registered a servlet mapping for <filename>/rest</filename> in
                    <filename>web.xml</filename>, we would need to make sure that this path is
                ignored in our main <filename>controller.xql</filename>. However, if the mapping is
                done via <filename>controller-config.xml</filename>, it will already been known to
                XQueryURLRewrite and we don't need take care of the path in our controller.</para><para>The <sgmltag>root</sgmltag> elements define the roots of a directory or database
                collection hierarchy, mapped to a certain base path. For example, the default
                    <filename>controller-config.xml</filename> uses two roots:</para><synopsis language="xml">&lt;!-- 
 Default configuration: main web application is served from the
 webapp directory. 
--&gt;
&lt;root pattern="/tools" path="xmldb:exist:///db/www"/&gt;
&lt;root pattern=".*" path="/"/&gt;</synopsis><para>This means that paths starting with <filename>/tools</filename> will be mapped to
                the collection hierarchy below <filename>/db/www</filename>. Everything else is
                handled by the catch all pattern pointing to the root directory of the webapp (by
                default corresponding to <filename>EXIST_HOME/webapp</filename>). For example, the
                URI</para><synopsis>http://localhost:8080/exist/tools/admin/admin.xql</synopsis><para>will be handled by the controller stored in database collection <filename>/db/www/admin/</filename> (if there is one) or will directly resolve to
                    <filename>/db/www/admin/admin.xql</filename>. In this case, all relative or
                absolute URIs within the controller will be resolved against the database, not the
                file system. However, there's a possibility to escape this path interpretation, described
                <ulink url="#EXTERNAL_RESOURCES">below</ulink>.</para></section><section><title>MVC and Pipelines</title><para>XQueryURLRewrite does more than just forward or redirect requests: the response
                can be further processed by passing it to a pipeline of views. "Views" are again
                just plain Java servlets. The most common use of a view would be to post-processes
                the XML returned from the primary URL, either through another XQuery or an XSLT
                stylesheet (XSLTServlet). XQueryURLRewrite passes the HTTP response stream of the
                previous servlet to the HTTP request received by the next servlet. Views may also
                directly exchange information through the use of request attributes (more on that
                below).</para><para>You define a view pipeline by adding a <sgmltag>view</sgmltag> element to the
                    <sgmltag>dispatch</sgmltag> fragment returned from the controller. The
                    <sgmltag>view</sgmltag> element is just a wrapper around another sequence of
                    <sgmltag>forward</sgmltag> or <sgmltag>rewrite</sgmltag> actions.</para><para>For example, most of the documentation that comes with eXist is written in the
                docbook format and needs to be send through an XSLT stylesheet (<filename>webapp/stylesheets/db2html.xsl</filename>) to be transformed into HTML. This is
                done by returning the following <sgmltag>dispatch</sgmltag> fragment from <filename>webapp/controller.xql</filename>:</para><programlisting language="xml">&lt;dispatch xmlns="http://exist.sourceforge.net/NS/exist"&gt;
	&lt;view&gt;
		&lt;forward servlet="XSLTServlet"&gt;
			&lt;set-attribute name="xslt.stylesheet" 
				value="stylesheets/db2html.xsl"/&gt;
		&lt;/forward&gt;
	&lt;/view&gt;
    &lt;cache-control cache="no"/&gt;
&lt;/dispatch&gt;</programlisting><para>There's no forwarding action outside the view in this example, so the request will
                be handled by the servlet engine in the normal way. The response is then passed to
                XSLTServlet. A new HTTP POST request is created whose body is set to the response
                data of the previous step. XSLTServlet gets the path to the stylesheet from the
                request attribute "xslt.stylesheet" and applies it to the data.</para><para>If any step in the pipeline generates an error or returns an HTTP status code
                &gt;= 400, the pipeline processing will stop and the response is send back to the
                client immediately. The same happens if the first step returns with an HTTP status
                304 (NOT MODIFIED), which indicates that the client can use the version it has
                cached.</para><para>We can also pass a request through more than one "view". The following fragment
                applies two stylesheets in sequence (code taken from <filename>webapp/xquery/controller.xql</filename>):</para><example><title>Applying more than one stylesheet</title><programlisting language="xquery">if ($name eq 'acronyms.xql') then
	&lt;dispatch xmlns="http://exist.sourceforge.net/NS/exist"&gt;
		&lt;!-- query results are passed to XSLT servlet via request attribute --&gt;
		&lt;set-attribute name="xquery.attribute"
			value="model"/&gt;
		&lt;view&gt;
			&lt;forward servlet="XSLTServlet"&gt;
				&lt;set-attribute name="xslt.input"
					value="model"/&gt;
				&lt;set-attribute name="xslt.stylesheet"
					value="xquery/stylesheets/acronyms.xsl"/&gt;
			&lt;/forward&gt;
			&lt;forward servlet="XSLTServlet"&gt;
				&lt;clear-attribute name="xslt.input"/&gt;
				&lt;set-attribute name="xslt.stylesheet" 
					value="stylesheets/db2html.xsl"/&gt;
			&lt;/forward&gt;
		&lt;/view&gt;
	&lt;/dispatch&gt;</programlisting></example><para>The example also demonstrates how information can be passed between actions.
                XQueryServlet - which is called implicitely because the URL ends with ".xql" - can
                save the results of the called XQuery to a request attribute instead of writing them
                to the HTTP output stream. It does so if it finds a request attribute
                    <option>xquery.attribute</option>, which should contain the name of the
                attribute the output should be saved to.</para><para>In the example above, <option>xquery.attribute</option> is set to "model". This
                causes XQueryServlet to fill the request attribute <option>model</option> with the
                results of the XQuery it executes. The query result will not be written to the HTTP
                response as you would normally expect. The HTTP response body will just be
                empty.</para><para>Likewise, XSLTServlet can take its input from a request attribute instead of
                parsing the HTTP request body. The name of the request attribute should be given in
                attribute <option>xslt.model</option>. XSLTServlet discards the current request
                content (which is empty anyway) and uses the data in the attribute's value as input
                for the transformation process.</para><para>XSLTServlet will always write to the HTTP response. The second invocation of
                XSLTServlet thus needs to read its input from the HTTP request body which contains
                the response of the first servlet. Since request attributes are preserved throughout
                the entire pipeline, we need to clear the <option>xslt.input</option> with an
                explicit call to clear-attribute.</para><para>What benefits does it have to exchange data through request attributes? Well, we
                save one serialization step: XQueryServlet directly passes the node tree of its
                output as a valid XQuery value, so XSLTServlet does not need to parse it
                again.</para><para>The advantages become more obvious if you have two or more XQueries which need to
                exchange information: XQuery 1 can use the XQuery extension function
                request:set-attribute() to save an arbitrary XQuery sequence to an attribute. XQuery
                2 then calls request:get-attribute() to retrieve this value. It can directly access
                the data passed in from XQuery 1. No time is lost with serializing/deserializing the
                data.</para><para>Let's have a look at a more complex example: the XQuery sandbox web application
                needs to execute a user-supplied XQuery fragment. The results should be retrieved in
                an asynchronous way, so the user doesn't need to wait and the web interface remains
                usable.</para><para>Older versions of the sandbox used the <function>util:eval</function> function to
                evaluate the query. However, this has side-effects because util:eval executes the
                query within the context of another query. Some features like module imports will
                not work properly this way. To avoid util:eval, the controller code below passes the
                user-supplied query to XQueryServlet first, then post-processes the returned result
                and stores it into a session for later use by the ajax frontend:</para><example><title>Post-processing the results of an XQuery with a second XQuery</title><programlisting language="xquery">if (starts-with($path, '/sandbox/execute')) then
    let $query := request:get-parameter("qu", ())
    let $startTime := util:system-time()
    return
        &lt;dispatch xmlns="http://exist.sourceforge.net/NS/exist"&gt;
    		&lt;!-- Query is executed by XQueryServlet --&gt;
            &lt;forward servlet="XQueryServlet"&gt;
    			&lt;!-- Query is passed via the attribute 'xquery.source' --&gt;
                &lt;set-attribute name="xquery.source" value="{$query}"/&gt;
    			&lt;!-- Results should be written into attribute 'results' --&gt;
    			&lt;set-attribute name="xquery.attribute" value="results"/&gt;
    			&lt;!-- Errors should be passed through instead of terminating the request --&gt;
    			&lt;set-attribute name="xquery.report-errors" value="yes"/&gt;
            &lt;/forward&gt;
    		&lt;view&gt;
    			&lt;!-- Post process the result: store it into the HTTP session
    				and return the number of hits only. --&gt;
    			&lt;forward url="session.xql"&gt;
    				&lt;clear-attribute name="xquery.source"/&gt;
    				&lt;clear-attribute name="xquery.attribute"/&gt;
    				&lt;set-attribute name="elapsed" 
    					value="{string(seconds-from-duration(util:system-time() - $startTime))}"/&gt;
    			&lt;/forward&gt;
    		&lt;/view&gt;
        &lt;/dispatch&gt;
    (: Retrieve an item from the query results stored in the HTTP session. The
    format of the URL will be /sandbox/results/X, where X is the number of the
    item in the result set :)
    else if (starts-with($path, '/sandbox/results/')) then
    &lt;dispatch xmlns="http://exist.sourceforge.net/NS/exist"&gt;
    	&lt;forward url="../session.xql"&gt;
    		&lt;add-parameter name="num" value="{$name}"/&gt;
    	&lt;/forward&gt;
    &lt;/dispatch&gt;</programlisting></example><para>The client passes the user-supplied query string in a request parameter, so the
                controller has to forward this to XQueryServlet somehow. Fortunately, XQueryServlet
                has an option to read the XQuery source from a request attribute,
                    <option>xquery.source</option>. The query result will be saved to the attribute
                    <option>results</option>. The second XQuery, <filename>session.xql</filename>,
                takes the result and stores it into a HTTP session, returning only the number of
                hits and the elapsed time.</para><para>When called through retrieve, <filename>session.xql</filename> looks at parameter
                    <option>num</option> and returns the item at the corresponding position from the
                query results stored in the HTTP session.</para></section><section><title>Controller XML Format</title><para>A controller XQuery is expected to return a single XML element:
                    <sgmltag>dispatch</sgmltag> in the eXist namespace:
                    <uri>http://exist.sourceforge.net/NS/exist</uri>. <sgmltag>dispatch</sgmltag>
                may contain a single action element, followed by an optional <sgmltag>view</sgmltag>
                element. Two action elements are currently allowed:</para><variablelist><varlistentry><term>redirect</term><listitem><para>Redirects the client to another URL, indicating that the other URL
                            should be used for subsequent requests. The URL to redirect to is given
                            in attribute <option>url</option>. A redirect will usually be visible to
                            the user.</para></listitem></varlistentry><varlistentry><term>forward</term><listitem><para>Forwards the current request to another request path or servlet. The
                            forwarding is done on the server only, via the RequestDispatcher of the
                            servlet engine. The client can't see where the request was forwarded
                            to.</para><para>The request can either be forwarded to a servlet or to another request
                            path, depending on which attribute is specified:</para><variablelist><varlistentry><term>url</term><listitem><para>The new request path, which will be processed by the
                                        servlet engine in the normal way, as if it were directly
                                        called. A relative path will be relative to the current
                                        request path. Absolute path will be resolved relative to the
                                        current web context. For example, if the current web context
                                        is <filename>/exist</filename> and the supplied attribute
                                        reads <option>url="/admin"</option>, the resulting path will
                                        be <filename>/exist/admin</filename>.</para></listitem></varlistentry><varlistentry><term>servlet</term><listitem><para>The name of a servlet as given in the
                                            <option>servlet-name</option> element in the
                                        corresponding servlet definition of the web descriptor,
                                            <filename>web.xml</filename>. For example, valid names
                                        within the eXist standard setup would be "XQueryServlet" or
                                        "XSLTServlet".</para></listitem></varlistentry><varlistentry><term>absolute</term><listitem><para>To be used in combination with <option>url</option>. If
                                        set to "yes", the url will be interpreted as an absolute
                                        path within the current servlet context. See <ulink url="#EXTERNAL_RESOURCES">below</ulink> for an
                                        example.</para></listitem></varlistentry><varlistentry><term>method</term><listitem><para>The HTTP method (POST, GET, PUT ...) to use when passing
                                        the request to the pipeline step (does not apply to the
                                        first step). This is important if the servlet or URL does
                                        not support all methods. The default method for pipeline
                                        steps in the view section is always POST.</para></listitem></varlistentry></variablelist></listitem></varlistentry></variablelist><para>In addition to the action, an element <sgmltag>cache-control</sgmltag> may
                appear:</para><variablelist><varlistentry><term>cache-control</term><listitem><para>has a single attribute <option>cache="yes|no"</option>. the
                            cache-control element is used to tell XQueryURLRewrite if the current
                            URL rewrite should be cached. Internally, XQueryURLRewrite keeps a map
                            of input URIs to dispatch rules. With the cache enabled, the controller
                            XQuery does only need to be executed once for every input URI.
                            Subsequent requests will use the cache.</para><para>However, only the URL rewrite rule is cached, not the HTTP response.
                            The cache-control setting has nothing to do with the corresponding HTTP
                            cache headers or client-side caching within the browser.</para></listitem></varlistentry></variablelist><para>Within an action element, parameters and attributes can be set as follows:</para><variablelist><varlistentry><term>add-parameter</term><listitem><para>Add (or overwrite) a request parameter. The original HTTP request will
                            be copied before the change is applied. Subsequent steps in the pipeline
                            will not see the parameter. The name of the parameter is taken from
                            attribute <option>name</option>, the value from attribute
                                <option>value</option>.</para></listitem></varlistentry><varlistentry><term>set-attribute</term><listitem><para>Set a request attribute to the given value. The name of the attribute
                            is read from attribute <option>name</option>, the value from attribute
                                <option>value</option>. You can set arbitrary request attributes,
                            e.g. to pass information between XQueries. However, some attributes may
                            be reserved by the called servlet (see examples above).</para></listitem></varlistentry><varlistentry><term>clear-attribute</term><listitem><para>Clears a request attribute. Unlike parameters, request attributes will
                            be visible to subsequent steps in the processing pipeline. They does
                            need to be cleared once they are no longer needed. The name of the
                            attribute is read from attribute <option>name</option>.</para></listitem></varlistentry><varlistentry><term>set-header</term><listitem><para>Set an HTTP response header field. The HTTP response is shared between
                            all steps in the pipeline, so all following steps will be able to see
                            the changed header.</para></listitem></varlistentry></variablelist></section><section id="EXTERNAL_RESOURCES"><title>Accessing resources not stored in the database</title><para>If your controller.xql is stored in a database collection, all relative or
                absolute URIs within the controller will be resolved against the database, not the
                file system. This can be a problem if you need to acess common resources, which
                should be shared with other applications residing on the file system or in the
                database.</para><para>The <sgmltag>forward</sgmltag> directive accepts an optional attribute
                    <option>absolute="yes|no"</option> to handle this. If one sets
                    <option>absolute="yes"</option>, an absolute path (starting with a /) specified
                in the <option>url</option> attribute will be resolved relative to the current
                servlet context, NOT the controller context.</para><para>For example, to forward all requests starting with a path
                    <filename>/libs/</filename> to a directory within the
                    <filename>webapp</filename> folder of eXist, you can use the following
                snippet:</para><example><title>Mapping all requests starting with /libs/ to a directory</title><programlisting language="xquery">
if (starts-with($exist:path, "/libs/")) then
    &lt;dispatch xmlns="http://exist.sourceforge.net/NS/exist"&gt;
        &lt;forward url="/{substring-after($exist:path, '/libs/')}" absolute="yes"/&gt;
    &lt;/dispatch&gt;</programlisting></example><para>This simply removes the /libs/ prefix and sets absolute="yes", so the path will be
                resolved relative to the main context of the servlet engine, usually /exist/. In your HTML, you can now
                write:</para><synopsis language="xml">&lt;script type="text/javascript" src="/libs/scripts/jquery/jquery-1.7.1.min.js"&gt;&lt;/script&gt;</synopsis><para>This will locate the jquery file in <filename>webapp/scripts/jquery/...</filename>, even if the rest of your
                application is stored in the db and not on the file system.</para></section><section><title>Special Attributes Accepted by eXist Servlets</title><para>eXist's XQueryServlet as well as the XSLTServlet will listen to a few, predefined
                request attributes. The names of those attributes are listed below and should not be
                used for other purposes.</para><section><title>XQueryServlet</title><variablelist><varlistentry><term>xquery.attribute</term><listitem><para>Should contain the name of a request attribute, if set. Instead of
                                writing query results to the response output stream, XQueryServlet
                                will store them into the named attribute. The value of the attribute
                                will be an XQuery Sequence
                                    (<classname>org.exist.xquery.Sequence</classname>). If no query
                                results were returned, the attribute will contain an empty
                                sequence.</para></listitem></varlistentry><varlistentry><term>xquery.source</term><listitem><para>If set, the value of this attribute should contain the XQuery code
                                to execute. Normally, XQueryServlet reads the XQuery from the file
                                given in the request path. <option>xquery.source</option> is a way
                                to overwrite this behaviour, e.g. if you want to evaluate an XQuery
                                which was generated within the controller.</para></listitem></varlistentry><varlistentry><term>xquery.module-load-path</term><listitem><para>The path which will be used for locating modules. This is only
                                relevant in combination with <option>xquery.source</option> and
                                tells the XQuery engine where to look for modules imported by the
                                query. For example, if you stored required modules into the database
                                collection <filename>/db/test</filename>, you can set
                                    <option>xquery.module-load-path</option> to
                                "xmldb:exist:///db/test". If the query contains an
                                expression:</para><synopsis language="xquery">import module namespace test="http://exist-db.org/test" at "test.xql";</synopsis><para>the XQuery engine will try to find the module
                                    <filename>test.xql</filename> in the filesystem by default,
                                which is not what you want. Setting
                                    <option>xquery.module-load-path</option> fixes this.</para></listitem></varlistentry><varlistentry><term>xquery.report-errors</term><listitem><para>If set to "yes", an error in the XQuery will not result in an HTTP
                                error. Instead, the string message of the error is enclosed in an
                                element <sgmltag>error</sgmltag> which is then written to the
                                response stream. The HTTP status is not changed.</para></listitem></varlistentry></variablelist></section><section><title>XSLTServlet</title><variablelist><varlistentry><term>xslt.stylesheet</term><listitem><para>The path to the XSL stylesheet. Relative paths will be resolved
                                against the current request URI, absolute paths against the context
                                of the web application (/exist). To reference a stylesheet which is
                                stored in the database, use an XML:DB URI, e.g. <filename>xmldb:exist:///db/styles/myxsl.xsl</filename>.</para></listitem></varlistentry><varlistentry><term>xslt.input</term><listitem><para>Contains the name of a request attribute from which the input to
                                the transformation process should be taken. The input has to be a
                                valid eXist XQuery sequence or an error will be thrown.</para><para>This attribute is usually combined with
                                    <option>xquery.attribute</option> provided by XQueryServlet and
                                allows passing data between the two without additional
                                serialization/parsing overhead.</para></listitem></varlistentry><varlistentry><term>xslt.user</term><listitem><para>The name of the eXist user which should be used to read and apply
                                the stylesheet.</para></listitem></varlistentry><varlistentry><term>xslt.password</term><listitem><para>Password for the user given in <option>xslt.user</option></para></listitem></varlistentry></variablelist><para>XSLTServlet will attempt to map all other request attributes starting with the
                    prefix <option>xslt.</option> into <emphasis>stylesheet parameters</emphasis>.
                    So, for example, if you set a request attribute <option>xslt.myattr</option> it
                    will be available within the stylesheet as parameter
                        <option>$xslt.myattr</option>. For security reasons, this is the only way to
                    pass request parameters into the stylesheet: use the controller query to
                    transform the request parameter into a request attribute and pass that to the
                    view.</para><para>However, depending on the XSLT engine used, automatic conversion of types
                    between eXist/Java and the XSLT processor may not always work. It might be good
                    to limit your attribute values to nodes or strings.</para></section></section></chapter></book>