XQuery/Searching, Paging and Sorting

These examples use a simple XML file containing data on Earthquakes around the world. The data come from Swivel. The examples use the generic table-viewer introduced in "Creating Custom Views" for output.

Searching
This example searches for a string in the location of the earthquake.

declare option exist:serialize "method=xhtml media-type=text/html indent=yes"; import module namespace wikiutil = "http://www.cems.uwe.ac.uk/xmlwiki" at "util.xqm";

let $search := request:get-parameter("search","") let $matches := //Earthquake[contains(Location,$search)] return Search Earthquakes for {$search} Search Earthquakes Search for  {      wikiutil:sequence-to-table($matches) }

Execute

Paging
This script implements paging of the search results. Here the full search is repeated for each call, with the state of the interaction held in a hidden input. declare option exist:serialize "method=xhtml media-type=text/html indent=yes"; import module namespace wikiutil = "http://www.cems.uwe.ac.uk/xmlwiki" at  "util.xqm";

let $search := request:get-parameter("search","") let $start:= xs:integer(request:get-parameter("start", "1")) let $records := xs:integer(request:get-parameter("records", "5")) let $action := request:get-parameter("action","search")

let $allMatches := //Earthquake[contains(Location,$search)]

(: compute the limits for this page :) let $max := count($result) let $start := if ($action = "Previous") then max(($start - $records, 1)) else if ($action="Next") then if ($max <$start +$records) then $start else $start +$records else if ($action="Search") then 1 else $start let $end := min (($start + $records - 1,$max)) (: restrict the full set of matches to this subsequence :) let $matches := subsequence($allMatches,$start,$records)

return Search Earthquakes Search Earthquakes Search Location for      Displaying {$start} to {$end} out of {$max} records found. {wikiutil:sequence-to-table($matches) } Records per Page 

Execute

Sorting
To get the columns sorted, we add a submit button to each column. This requires extending the generic table viewer to sort the nodes by the selected column.

declare function wikiutil:sequence-to-table($seq,$sort) { };

declare option exist:serialize "method=xhtml media-type=text/html indent=yes"; import module namespace wikiutil = "http://www.cems.uwe.ac.uk/xmlwiki" at  "util.xqm";

let $search := request:get-parameter("search","") let $sort := request:get-parameter("Sort","Date") let $matches := //Earthquake[contains(Location,$search)] return Search Earthquakes} Search Earthquakes Search Location for  {wikiutil:sequence-to-table($matches,$sort)}

Note that the sort is by string value: Sorting by magnitude succeeds only by chance, whereas the sort on Fatalities does not. Execute

An improvement would be to allow successive clicks to a column heading to reverse the sort direction. This requires the addition of two more items into the interaction state, the current sort order and current direction, and changes to the table generator. One would like to be able to say something like:

for $row .. let $sortBy := .. let $direction := if (..) then "ascending" else "descending" order by $sortBy $direction

but this is not a valid FLWOR expression. Instead we have to have two FLWOR expressions, one for each direction.

declare function wikiutil:sequence-to-table($seq,$sort,$direction) { };

Then the script becomes:

import module namespace wikiutil = "http://www.cems.uwe.ac.uk/xmlwiki" at  "util.xqm";

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

let $search := request:get-parameter("search","") let $sort := request:get-parameter("Sort","Date") let $lastSort := request:get-parameter("LastSort","") let $lastDirection := number(request:get-parameter("LastDirection","1")) let $direction := if ($lastSort = $sort) then - $lastDirection else 1 let $matches := //Earthquake[contains(Location,$search)] return Search Earthquakes Search Earthquakes Search Location for    { wikiutil:sequence-to-table($matches,$sort, $direction)   }

Execute

Using a table schema
Greater control over the output can be obtained by providing a schema for the table. This schema can specify the order of columns and column headings, and potentially conversion instructions as well.

We can provide the table schema as a sequence of Column definitions:

    

The schema-based function looks like:

declare function wikiutil:sequence-to-table-with-schema($seq,$schema) { };

Note the use of a XQuery idiom to compute the column heading as the supplied heading if there is one, otherwise the node name: ($column/@heading,$column/@name)[1]

This computes the first non-null item in the sequence, a cleaner and more generalisable alternative to: if (exists($column/@heading)) then $column/@heading else $column/@name

Execute