XQuery/Incremental Searching

Motivation
You have a large data set and you want to use JavaScript to asynchronously communicate with a server to narrow the scope of the search as a user types.

US Zip Code Example
There are around 43,000 5 digit ZipCodes in the US. There are a number of applications to convert a zip code to a location, for example Ben Fry's Java applet written using Processing

This example uses a client-side XHTML page using Ajax to request a subset of codes from a server-side search of an XML database of Zipcodes, updating the page dynamically.

The HTML page
Generated by an XQuery although the content is static.

declare option exist:serialize "method=xhtml media-type=text/html indent=yes";

 ZIP Code to City and State using XmlHttpRequest  US Zipcode decoder  ZIP code:  e.g. 95472

Javascript
Uses XMLHttpRequest to request the subset and innerHTML to update the page.

function updateList { if (http.readyState == 4) { var divlist = document.getElementById('list'); divlist.innerHTML = http.responseText; isWorking = false; } }

function getList { if (!isWorking && http) { var zipcode = document.getElementById("zip").value; http.open("GET", "getzip.xq?zipcode=" + escape(zipcode), true); 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;

XQuery search
The Server-side XQuery to perform the search in the XML database and generate the XHTML. This uses the eXist full text index and the exist-specific &= operator.

let $zipcode := request:get-parameter("zipcode",) return {if (string-length($zipcode) > 1)  (: too slow :) then let $search := concat('^',$zipcode) for $zip in //Zipcode[matches(Code,$search)] return {string-join(($zip/Code,$zip/Area,$zip/State),' ')} else }

XML data file
The data was originally a CSV file, converted to XML using Excel and the XML add-in. This is a sample of the data.

  Portsmouth NH   Portsmouth NH </Zipcode> <Zipcode> <Area>Portsmouth</Area> <State>NH</State> </Zipcode> <Zipcode> <Area>Portsmouth</Area> <State>NH</State> </Zipcode> ...

Execute