Writing Programs with XQuery
XQuery is XPath grown into a programming language. Every XPath expression is an XQuery query, and XQuery adds:
- FLWOR expressions, a powerful form of
forandlet, withwhere,order by,group by,countand windows; - constructors that build new XML, written as XML with expressions inside;
- a prolog of declarations: functions (which can call themselves), variables, namespaces, options and imported modules;
- updates, which insert, delete, replace and rename nodes.
This chapter works on the same document as Finding Things with XPath: the Vane protocol, an Internet-Draft written in XML. Its requirements are paragraphs with an anchor and a BCP 14 keyword:
<section anchor="pause">
<name>Pause</name>
<t anchor="req-7">After three failed checks in a row, a service
<bcp14>MUST</bcp14> put the flag in a <xref target="term-pause">pause</xref>.</t>
<t anchor="req-8">A pause <bcp14>SHOULD</bcp14> last five minutes.
<cref anchor="issue-1" source="AM">Should an owner be able to
change the duration?</cref></t>
<t anchor="req-11">A service <bcp14>MAY</bcp14> report a pause to the
owners of the flag as soon as it begins.</t>
</section>
There is an earlier version of the draft too, vane-00.xml, and the
chapter compares the two. The examples run in
docs/book/examples/spec, the directory of the specification project.
By the end of the chapter we'll have a small toolkit for that project: a
module that knows the draft's structure, a check that finds its
mistakes, a list of what changed between versions, and updates that edit
the draft in place, one named node at a time, instead of rewriting it.
Running a query
A query usually lives in a file, ending in .xq. sxml xquery runs it:
$ sxml xquery --context-item=vane.xml keywords.xq
1. MUST (5): req-1, req-2, req-4, req-6, req-7
2. MAY (2): req-9, req-11
3. SHOULD (2): req-3, req-8
Here is the query:
keywords.xq:
declare option output:method "text";
declare option output:item-separator " ";
for $requirement in //t[@anchor]
group by $keyword := string($requirement/bcp14)
let $count := count($requirement)
order by $count descending, $keyword
count $rank
where $rank le 3
return `{$rank}. {$keyword} ({$count}): {string-join($requirement/@anchor, ", ")}`
The first two lines are the prolog: here, two options for the output,
which ask for plain text with one item on each line ( is a line
feed, written as an XML character reference). The rest is the query
body, one FLWOR expression that groups the requirements by keyword,
counts them, sorts and ranks the groups, and keeps the first three. By
the end of the next section you'll be able to read every clause of it.
The same query runs on the earlier draft, which had no MAY yet:
$ sxml xquery --context-item=vane-00.xml keywords.xq
1. MUST (5): req-1, req-2, req-4, req-6, req-7
2. SHOULD (2): req-3, req-8
3. MUST NOT (1): req-5
For short queries, --expression saves writing a file. Unlike
sxml xpath, sxml xquery writes its result with the xml output
method by default, as a query's result is usually XML; --method
chooses another:
$ sxml xquery --context-item=vane.xml --expression='//section[@anchor = "pause"]/name'
<name>Pause</name>
$ sxml xquery --expression='for $i in 1 to 3 return <item>{ $i }</item>'
<item>1</item><item>2</item><item>3</item>
$ sxml xquery --method=adaptive --expression='"one", 2'
"one"
2
Comments
XQuery comments are written between (: and :), and can be nested.
Comments that start with (:~ document the declaration after them:
(: A comment. (: A nested one. :) :)
What's in this chapter
- FLWOR Expressions:
for,let,where,order by,group by,countandwhile; - Grouping: putting requirements together by section and by keyword;
- Building XML: constructors and namespaces, for an XHTML index of the requirements;
- Conditions, Types and Errors:
switch,typeswitch, sequence types,tryandcatch; - Functions and Modules: declared functions, library modules and private helpers;
- Documents, Parameters and the Context: the input of a query, both drafts at once, and external variables;
- Writing Results: output methods and serialization parameters;
- Updating Documents: the XQuery Update Facility, for edits that touch only the nodes they name;
- What's New in XQuery 4.0: a tour for readers who know XQuery 3.1;
- Project: Editing a Specification Without Rewriting It: all of it in a toolkit for the draft.
Full-text search, with contains text, is part of XQuery in sxml too;
it is in Working with Text, with the other ways of working
with text. Windows, the FLWOR clauses for runs of neighbouring items,
are taught on trace data in
Who Calls Whom, and How Often, and
Project: Generating Vane's SDKs from a Schema uses XQuery to
build the tree of a TypeScript program.