XQuery/Incremental Search of the Chemical Elements
Introduction
editIn this example of AJAX in its AHAH form, an incremental search of the chemical elements is implemented. This is also an example of the use of matching with a regular expression.
The raw data is taken from a file [1]provided by Elliotte Rusty Harold.
Execution
editThe main page
editThe main page is a simple HTML file. The div element with id list is where the generated contents will be placed. The JavaScript function getList() is called when any of several interface events occur.
declare option exist:serialize "method=xhtml media-type=text/html
doctype-public=-//W3C//DTD HTML 4.01 Transitional//EN
doctype-system=http://www.w3.org/TR/loose.dtd";
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Chemical Elements</title>
<script language="javascript" src="ajaxelement.js"/>
<style type="text/css">
td {{background-color: #efe; font-size:14px;}}
th {{background-color: #ded; text-align: right; font-variant:small-caps;padding:3px; font-size:12px;}}
</style>
</head>
<body>
<h1>Chemical Elements</h1>
<table class="page">
<tr>
<td valign="top" width="30%"><form onSubmit="getList(); return false">
<span><label for="name">Element Name </label>
<input type="text" size="5" name="name" id="name" title="e.g. Silver"
onkeyup="getList();" onfocus="getList();" />
</span>
</form>
</td>
<td id="list"/>
</tr>
</table>
</body>
</html>
The JavaScript
editThe JavaScript implements the simple functionality of calling the server-side script getElement.xq with the string entered in the search box, and in the callback, pasting the returned XHTML into the div. [ This JavaScript uses no supporting libraries although it would be simplified by using e.g. jQuery ]
function updateList() {
if (http.readyState == 4) {
var divlist = document.getElementById('list');
divlist.innerHTML = http.responseText;
isWorking = false;
}
}
function getList() {
if (!isWorking && http) {
var name = document.getElementById("name").value;
http.open("GET", "getElement.xq?name=" + name);
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;
The server-side search
editThis script is called by the getlist() function when a partial atom name has been entered. The string is converted to a simple regular expression and used in the eXist free text matching function to retrieve matching atoms. The response depends on the number of matches found:
- if only one match, return a table of details
- if more than one match, return with a list of matches
- if none return "no matches"
A function turns the ATOM node into a table,mapping each child node to a row with the node name as the legend.
declare function local:atom-to-table($element ) {
<table class="element">
{for $node in $element/*
let $label := replace(name($node),"_"," ")
return
<tr>
<th>{$label}</th>
<td>
{ $node/text() }
</td>
</tr>
}
</table>
};
let $name := request:get-parameter("name",())
return
if ($name != "")
then
let $search := concat('^',$name) (: anchor the term to the start of the string :)
let $elements := doc("periodicTable.xml")/PERIODIC_TABLE
let $matches := $elements/ATOM[matches(NAME,$search,"i")]
return
if (count($matches) = 0)
then
<span>No matches</span>
else
if (count($matches) =1)
then
local:atom-to-table($matches)
else
(: multiple matches :)
<table class="list">
<tr>
<th>Name</th>
<th>Symbol</th>
<th>Atomic Weight</th>
</tr>
{for $match in $matches
order by $match/NAME
return
<tr>
<th>{string($match/NAME)}</th>
<td>{string($match/SYMBOL)}</td>
<td>{string($match/ATOMIC_WEIGHT)} </td>
</tr>
}
</table>
else ()
To do
editSome naming problems here - needs tidying. Units need to be included