Jump to content

XForms/eXist

From Wikibooks, open books for an open world

eXist is a native XML database that has a full REST interface. This allows you to use eXist to save form data without writing any middleware glue.

eXist REST interface

[edit | edit source]

eXist provides a full REST interface that is easy to call from an XForm.

eXist WebDAV interface

[edit | edit source]

eXist also provides a full WebDAV interface. This allows you to do HTTP "PUT" operations directly from your forms.

eXist Example

[edit | edit source]

In this example, we will create a user named "juser" (Jane User) and setup a collection to read and write form data.

Sample Program

[edit | edit source]

To run this program, just install eXist from the [1] web site. use the eXist admin menu to create a user called "juser". Then create a home collection for juser at /db/home/juser. Then login as juser and create a collection called "test". You will put a form and instance data into this file.

To read and write instance data into a form just use the following example:

<html>
   <head>
      <xf:model>
         <xf:instance id="data-instance" src="data.xml" xmlns=""/>
         <xf:submission id="read-from-file"
            method="get"
            action="http://localhost:8080/exist/rest/db/home/juser/test/data.xml" 
            replace="instance" instance="data-instance"/>
         <xf:submission id="save-to-file"
            method="put"
            action="http://localhost:8080/exist/webdav/db/home/juser/test/data.xml"
            replace="instance" instance="data-instance"/>
      </xf:model>
   </head>
...

Note that if the data is in the same collection as the form (not a good long term design) you can use a relative path reference. Also note that we are doing an HTTP PUT operation to the webdav (not rest) interface to exist.

Using eXist URLs

[edit | edit source]

It is easy to load XML data directly into your XForms application. In the instance statement in your model just add a src attribute and put a path name to the file you want to edit. The key is to put the word "rest" in the URL when you are reading data into your form:

  <xf:instance id="my-form-data" xmlns="" src="http://localhost:8080/exist/rest/db/home/juser/test/data.xml"/>

Always put the word "webdav" in the URL path when doing an HTTP PUT.

 http://localhost:8080/exist/webdav/db/home/juser/test/data.xml

That is all there is to it!

For more information see the eXist manual on using the REST and WebDAV interfaces for eXist.

Using XQuery to return Document IDs

[edit | edit source]

When using an XML database, you sometimes wish to have the database receive an XML document and store it in the correct location based on business rules such as the content of an XML document and the date. This can be done in relational databases using stored procedures.

XQuery can be thought of as an XML-oriented stored procedure. eXist allows you to save directly to the URL of an XQuery and the XQuery can store the document based on a number of rules.

Here is an example eXist XQuery that that takes HTTP POST and creates a path name to a collection based on the county in input document and the date. After it saves the file and checks that the save has worked it increments a counter similar to the AUTOINCREMENT property of some relational databases.

xquery version "1.0";

(: Save-crv.xq Version 0.1, Dan McCreary, March 2nd 2007:)

declare namespace request="http://exist-db.org/xquery/request";
declare namespace xmldb="http://exist-db.org/xquery/xmldb";

declare namespace c="http://niem.gov/niem/common/1.0" ;
declare namespace u="http://niem.gov/niem/universal/1.0" ;
declare namespace mn="http://data.state.mn.us" ;
declare namespace mnr="http://revenue.state.mn.us" ;
declare namespace mnr-ptx="http://propertytax.state.mn.us" ;

declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance";

(: to store a CRV into the right location in exist we need 1) the county ID, 2) the date, 3) the sequence number :)

(: get the data from an HTTP post :)
let $crv := request:get-data()
let $count := count($crv//node())
let $county-id := $crv//eCRVDocument/RealProperty/RealPropertyLegalDescriptions/mnr-ptx:MNCountyID/text()
(: let $county-id := '19' :)
let $current-year := substring(string(current-date()),1, 4)
let $current-year-2 := substring(string(current-date()),3, 2)

(: let $collection := xmldb:collection(concat('xmldb:exist:///db/crv/data', $county-id, '/', $current-year), "dan", "dan123") :)

let $county-name := doc('/db/crv/data/admin/next-county-crvid.xml')//County[CodeID=$county-id]/Code
(: get the next-id from the sequence counter :)
let $next-id := doc('/db/crv/data/admin/next-county-crvid.xml')//County[CodeID=$county-id]/NextID
let $file-name := concat($next-id, '.xml')

let $collection-string := concat('xmldb:exist:///db/crv/data/', $county-name, '/', $current-year)
let $full-path := concat($collection-string, '/', $file-name)

(: ready to login and store a file :)

let $collection := xmldb:collection($collection-string, "login", "password")
let $retStore := xmldb:store($collection-string, $file-name, <eCRVDocument>{$crv/*}</eCRVDocument>)

(: If the file that we attempted to store does eXist, then now it is OK to increment the sequence counter for the next user :)
let $retCode1 :=  if (doc($full-path))
   then ( update replace doc("/db/crv/data/admin/next-county-crvid.xml")//County[CodeID=$county-id]/NextID with
            <NextID>{$next-id + 1}</NextID> )
   else ()

return 
<data>
  <county-id>{$county-id}</county-id>
  <current-year>{$current-year-2}</current-year>
  <sequence-id>{$next-id - 1}</sequence-id>
</data>

Processing the Results

[edit | edit source]

This XQuery returns an XML message such as the following

  <data>
    <county-id>19</county-id>
    <current-year>07</current-year>
    <sequence-id>47</sequence-id>
  </data>

Assuming you have a hostname, port and application-name variables are set up, the XForms application would contain the following code:

<xf:model>
...
   <xf:submission id="submit-validate-a1" method="post" 
      action="http://{$hostname}:{$exist-port}/{$application-name}/submit"
      replace="instance" instance="submit-result">
         <xf:toggle case="case-busy" ev:event="xforms-submit" />
         <xf:toggle case="case-submit-error" ev:event="xforms-submit-error" />
         <xf:toggle case="case-done" ev:event="xforms-submit-done" />
   </xf:submission>
...
</xf:model>
...
<body>
...
<xf:case id="case-done">
   <xf:group ref="instance('submit-result')">
      <h1 class="result-text">Your ID is = 
      <xf:output ref="county-id"/>-<xf:output ref="current-year"/>-<xf:output ref="sequence-id"/></h1>
   </xf:group>
...               
</xf:case>

Setting the mime type for XQuery Results

[edit | edit source]

If you want your XQuery to return the correct mime type put the following in the preamble:

declare option exist:serialize "method=xhtml media-type=text/xml indent=yes omit-xml-declaration=no";
declare namespace util="http://exist-db.org/xquery/util";
...
let $ret-code := util:declare-option("exist:serialize", "media-type=text/xml")

(This suggestion from Kurt Cagle)

declare option exist:serialize "method=3Dxhtml indent=3Dyes
omit-xml-declaration=3Dno
doctype-public=3D-//W3C//DTD&#160;XHTML&#160;1.1//EN
doctype-system=3Dhttp://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd";


Next Page: IBM DB2 | Previous Page: XML Databases
Home: XForms