XQuery/Navigating Collections
< XQuery
Motivation
editYou want to browse collections using an HTML web page and narrow your choices as you type.
Method
editWe 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
editget-child-collections.xq
editxquery 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)
return
<div class="results">{
if (count($sub-collections) = 0)
then
<h1>There are no subcollections of {$collection}</h1>
else
<div class="selections">{
for $child in $sub-collections
let $child-path := concat($parent, '/', $child)
order by $child
return
if (starts-with($child, $leaf))
then
<div class="selection"><a href="browse-collection.xq?collection={$child-path}/">{$child}</a></div>
else ()
}</div>
}</div>
browse-collection.xq
editxquery version "1.0";
declare option exist:serialize "method=xhtml media-type=text/html omit-xml-declaration=no indent=yes
doctype-public=-//W3C//DTD XHTML 1.0 Transitional//EN
doctype-system=http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";
let $title := "Browse Collections (AJAX)"
let $collection := request:get-parameter("collection", '/db/')
return
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>{$title}</title>
<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;}}
</style>
</head>
<body onload="getList();">
<h1>{$title}</h1>
<p>{$collection}</p>
<form onsubmit="getList(); return false" action="get">
<span>
<label for="collection">Collection:</label>
<input type="text" size="50" name="collection" id="collection" title="collection"
onkeyup="getList();" onfocus="getList();" value="{$collection}"/>
</span>
</form>
<!-- this is where the results are placed -->
<div id="results"/>
</body>
</html>
ajax-collection.js
editfunction 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;
http.send(null);
}
}
function getHTTPObject() {
var xmlhttp;
/*@cc_on
@if (@_jscript_version >= 5)
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (E) {
xmlhttp = false;
}
}
@else
xmlhttp = false;
@end @*/
if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
try {
xmlhttp = new XMLHttpRequest();
xmlhttp.overrideMimeType("text/xml");
} catch (e) {
xmlhttp = false;
}
}
return xmlhttp;
}
var http = getHTTPObject(); // create the HTTP Object
var isWorking = false;