XQuery/Navigating Collections

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

Motivation[edit | edit source]

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

Method[edit | edit source]

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 | edit source]

get-child-collections.xq[edit | edit source]

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 ()

browse-collection.xq[edit | edit source]

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"/>

ajax-collection.js[edit | edit source]

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;