XQuery/搜尋、分頁和排序
外觀
< XQuery
(重定向自 XQuery/搜尋、分頁和排序)這些示例使用一個簡單的 XML 檔案,其中包含有關全球地震的資料。該 資料 來自 Swivel。這些示例使用在“建立自定義檢視”中介紹的通用表格檢視器進行輸出。
此示例在地震發生位置搜尋字串。
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
<html>
<head>
<title>Search Earthquakes for {$search}</title>
</head>
<body>
<h1>Search Earthquakes</h1>
<form>Search for <input type="text" name="search" value="{$search}"/>
</form>
{
wikiutil:sequence-to-table($matches)
}
</body>
</html>
此指令碼實現了搜尋結果的分頁。這裡對每次呼叫都重複完整的搜尋,互動狀態儲存在一個隱藏的輸入中。
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
<html>
<head>
<title>Search Earthquakes </title>
</head>
<body>
<h1>Search Earthquakes</h1>
<form >
Search Location for <input type="text" name="search" value="{$search}"/>
<input type="submit" name="action" value="Search"/>
<br/>
<input type="hidden" name="start" value="{$start}"/>
<input type="submit" name="action" value="Previous"/>
<input type="submit" name="action" value="Next"/>
<p>Displaying {$start} to {$end} out of {$max} records found.</p>
{wikiutil:sequence-to-table($matches) }
<p>Records per Page <input type="text" name="records" value="{$records}"/></p>
</form>
</body>
</html>
要對列進行排序,我們在每列新增一個提交按鈕。這需要擴充套件通用表格檢視器,以便按所選列對節點進行排序。
declare function wikiutil:sequence-to-table($seq,$sort) {
<table border="1">
<tr>
{for $node in $seq[1]/*
return <th><input type="submit" name="Sort" value="{name($node)}"/></th>
}
</tr>
{for $row in $seq
let $sortBy := data($row/*[name(.) = $sort])
order by $sortBy
return
<tr>
{for $node in $seq[1]/*
let $data := data($row/*[name(.)=name($node)])
return <td>{$data}</td>
}
</tr>
}
</table>
};
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
<html>
<head>
<title>Search Earthquakes}</title>
</head>
<body>
<h1>Search Earthquakes</h1>
<form>Search Location for <input type="text" name="search" value="{$search}"/>
{wikiutil:sequence-to-table($matches,$sort)}
</form>
</body>
</html>
請注意,排序是按字串值進行的:按震級排序僅在偶然情況下才能成功,而按死亡人數排序則不能成功。
改進方法是允許連續點選列標題以反轉排序方向。這需要在互動狀態中新增兩個專案,即當前排序順序和當前方向,並對錶格生成器進行更改。人們希望能夠說類似的話
for $row .. let $sortBy := .. let $direction := if (..) then "ascending" else "descending" order by $sortBy $direction
但這並不是有效的 FLWOR 表示式。相反,我們必須有兩個 FLWOR 表示式,每個方向一個。
declare function wikiutil:sequence-to-table($seq,$sort,$direction) {
<table border="1">
<tr>
{for $node in $seq[1]/*
return <th><input type="submit" name="Sort" value="{name($node)}"/></th>
}
</tr>
{ if ($direction = 1)
then
for $row in $seq
let $sortBy := data($row/*[name(.) = $sort])
order by $sortBy ascending
return
<tr>
{for $node in $seq[1]/*
let $data := data($row/*[name(.)=name($node)])
return <td>{$data}</td>
}
</tr>
else
for $row in $seq
let $sortBy := data($row/*[name(.) = $sort])
order by $sortBy descending
return
<tr>
{for $node in $seq[1]/*
let $data := data($row/*[name(.)=name($node)])
return <td>{$data}</td>
}
</tr>
}
</table>
};
然後指令碼變為
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
<html>
<head>
<title>Search Earthquakes</title>
</head>
<body>
<h1>Search Earthquakes</h1>
<form>Search Location for <input type="text" name="search" value="{$search}"/>
<input type="hidden" name="LastSort" value="{$sort}"/>
<input type="hidden" name="LastDirection" value="{$direction}"/>
{ wikiutil:sequence-to-table($matches,$sort, $direction) }
</form>
</body>
</html>
可以透過提供表格模式來獲得對輸出的更多控制。此模式可以指定列的順序和列標題,以及潛在的轉換說明。
我們可以將表格模式提供為一系列 Column 定義
<Schema>
<Column name="Location" heading="Earthquake location"/>
<Column name="Magnitude" heading="Magnitude (Richter Scale)"/>
<Column name="Date" />
</Schema>
基於模式的函式如下所示
declare function wikiutil:sequence-to-table-with-schema($seq,$schema) {
<table border="1">
<tr>
{for $column in $schema/Column
return <th>{string( ($column/@heading,$column/@name)[1])}</th>
}
</tr>
{for $row in $seq
return
<tr>
{for $column in $schema/Column
let $data := data($row/*[name(.)=$column/@name])
return <td>{$data}</td>
}
</tr>
}
</table>
};
請注意,使用 XQuery 習慣用法來計算列標題,如果存在標題則使用提供的標題,否則使用節點名稱
($column/@heading,$column/@name)[1]
這會計算序列中第一個非空專案,這是一個比以下方法更簡潔、更通用的替代方案
if (exists($column/@heading)) then $column/@heading else $column/@name