XQuery/Navigating Collections

From Wikibooks, open books for an open world
Jump to navigation Jump to search


You want to browse collections using an HTML web page and narrow your choices as you type.


We will first create a server-side script that takes a single parameter. This is the collection path that the user is entering into an input field in a web page. With each character the user types the list of possible sub-collections is narrowed.

There are three parts to this script: 1) the server side XQuery script 2) the HTML form 3) the JavaScript file that implements the JavaScript with AJAX functions.

Sample Server-Side Script[edit]


xquery version "1.0";
declare function local:substring-before-last-slash($arg as xs:string?)  as xs:string {
if (matches($arg, '/'))
   then replace($arg,'^(.*)/.*','$1')   (: by default matching is eager :)
   else ''

(: if we don't get any value then use the root collection :)
let $collection := request:get-parameter("collection", '')
let $parent := local:substring-before-last-slash($collection)
let $leaf := substring-after($collection, concat($parent, '/'))

let $sub-collections := xmldb:get-child-collections($parent)

<div class="results">{
   if (count($sub-collections) = 0)
        <h1>There are no subcollections of {$collection}</h1>
      <div class="selections">{
         for $child in $sub-collections
         let $child-path := concat($parent, '/', $child)
         order by $child
            if (starts-with($child, $leaf))
                 <div class="selection"><a href="browse-collection.xq?collection={$child-path}/">{$child}</a></div>
            else ()


xquery version "1.0";
declare option exist:serialize "method=xhtml media-type=text/html omit-xml-declaration=no indent=yes 

let $title := "Browse Collections (AJAX)"

let $collection := request:get-parameter("collection", '/db/')

<html xmlns="http://www.w3.org/1999/xhtml" >
        <script type="text/javascript" src="ajax-collection.js"/>
        <style type="text/css">
            td {{background-color: #efe; font-size:14px;}}
            th {{background-color: #ded; text-align: right; padding:3px; font-size:12px;}}
    <body onload="getList();">
       <form onsubmit="getList(); return false" action="get">
                <label for="collection">Collection:</label> 
                <input type="text" size="50" name="collection" id="collection" title="collection"
                    onkeyup="getList();" onfocus="getList();" value="{$collection}"/>
        <!-- this is where the results are placed -->
        <div id="results"/>


function updateList() {
  if (http.readyState == 4) {
      var divlist = document.getElementById('results');
      divlist.innerHTML = http.responseText;
      isWorking = false;
function getList() {
  if (!isWorking && http) {
    var collectionid = document.getElementById("collection").value;
    http.open("GET", "get-child-collections.xq?collection=" + collectionid);
    http.onreadystatechange = updateList;  
          // this sets the call-back function to be invoked when a response from the HTTP request is returned
    isWorking = true;
function getHTTPObject() {
  var xmlhttp;
  @if (@_jscript_version >= 5)
    try {
      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (E) {
        xmlhttp = false;
  xmlhttp = false;
  @end @*/
  if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
    try {
      xmlhttp = new XMLHttpRequest();
    } catch (e) {
      xmlhttp = false;
  return xmlhttp;
var http = getHTTPObject(); //  create the HTTP Object
var isWorking = false;