Copyright © 2008 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark and document use rules apply.
This specification defines an extension to [XQuery 1.0] and [XQuery Update Facility]. Expressions can be evaluated in a specific order, with later expressions seeing the effects of the expressions that came before them. This specification introduces the concept of a block with local variable declarations, as well as several new kinds of expressions, including assignment, while, continue, break, and exit expressions.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This is a First Public Working Draft as described in the Process Document. It has been developed by the W3C XML Query Working Group, which is part of the XML Activity. The Working Group expects to advance this specification to Recommendation Status.
This document, published on 28 March 2008, represents the current status of its development. The WG believes that its development is sufficiently advanced to make it publicly visible to the community, who we hope will review it and submit comments on it. We particularly call your attention to our open E Issues.
No implementation report currently exists. However, a Test Suite for this document is under development.
Please report errors in this document using W3C's public Bugzilla system (instructions can be found at http://www.w3.org/XML/2005/04/qt-bugzilla). If access to that system is not feasible, you may send your comments to the W3C XSLT/XPath/XQuery public comments mailing list, public-qt-comments@w3.org. It will be very helpful if you include the string “[SX]” in the subject line of your report, whether made in Bugzilla or in email. Each Bugzilla entry and email message should contain only one error report. Archives of the comments and responses are available at http://lists.w3.org/Archives/Public/public-qt-comments/.
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
1 Introduction
2 Extensions to XQuery
1.0
2.1 Extensions to the Processing
Model
2.2 Extensions to the Prolog
2.2.1 Constants and Variables
2.2.2 Function Declarations
2.3 New Kinds of
Expressions
2.3.1 Assignment Expression
2.3.2 Block
2.3.3 Exit Expression
2.3.4 While Expression
2.3.5 Continue and Break Expressions
2.4 Changes to
Existing Expressions
2.4.1 Function Calls
2.4.2 FLWOR Expressions
2.4.3 Conditional Expressions
2.4.4 Typeswitch Expressions
2.4.5 Comma Expressions
2.4.6 Parentheses
2.4.7 Ordered and Unordered Expressions
2.4.8 Transform Expressions
2.4.9 Extension Expressions
2.4.10 Other Expressions
3 Example
A Summary of XQSE Grammar
Changes
B XML Syntax (XQueryX) for XQuery
Scripting Extension 1.0
B.1 Schema
B.2 Stylesheet
B.3 Example
B.3.1 XQuery Representation
B.3.2 XQueryX Representation
B.3.3 Transformed XQuery
Representation
C Implementation-Defined
Items
D References
E Issues
XQuery Scripting Extension extends [XQuery 1.0], enabling it to serve as a scripting language in order to satisfy [XQuery Scripting Requirements]. A prerequisite for this extension is [XQuery Update Facility]. The following abbreviations are used in this specification: [Definition: XQUF is an abbreviation for [XQuery Update Facility].] [Definition: XQSE is an abbreviation for XQuery Scripting Extension.]
XQSEhas the following properties:
It is a strict superset of XQUF, in the sense that all valid XQUF expressions are also valid XQSE expressions and have the same meaning. (In the same sense, XQUF is a strict superset of [XQuery 1.0].)
It does not introduce any "modes" that affect the semantics of expressions.
As in XQUF, the result of an expression consists of an XDM instance and a pending update list, at most one of which may be non-empty. [Definition: An XDM instance is an unconstrained sequence of zero or more nodes and/or atomic values, as defined in [XQuery Data Model].] [Definition: A pending update list is an unordered collection of update primitives, representing node state changes that have not yet been applied, as defined in [XQuery Update Facility].]
The principal extensions introduced by XQSE are as follows:
An ordering is defined on the evaluation of certain kinds of XQuery expressions. An implementation may use any execution strategy as long as the result complies with the semantics of this ordering. The ordering is defined in a way that places no additional constraints on the evaluation of any existing expressions.
Expressions in XQSE may have side-effects that are visible to subsequent expressions (according to the above ordering of evaluation).
XQSEintroduces the following new kinds of expressions:
Assignment expressions
Blocks
Exit expressions
While expressions
Continue expressions
Break expressions
XQSEintroduces a new expression category called sequential expressions. The expression categories introduced by XQUF (updating, simple, and vacuous expressions) are retained. Informal definitions of all the expression categories are summarized here. For normative definitions of the categories, see the "Category Rules" that are specified for each kind of expression in 2.3 New Kinds of Expressions and 2.4 Changes to Existing Expressions.
[Definition: An updating expression is an expression that can return a non-empty pending update list.] Updating expressions include insert, delete, replace, rename, and calls to updating functions, as well as certain other expressions that contain nested updating expressions. Note that, although an updating expression may return a non-empty pending update list, it does not actually apply any updates.
[Definition: A sequential expression is an expression that can have side effects other than constructing a new node or raising an error.] Side effects include applying updates to an XDM instance, altering the dynamic context, or affecting the flow of control. Sequential expressions include blocks, assignment, exit, while, continue, break, and calls to sequential functions, as well as certain other expressions that contain nested sequential expressions. The side effects of a sequential expression are immediately effective and are visible to subsequent expressions. Because of their side effects, sequential expressions must be evaluated in a well-defined order. In addition to its side effects, a sequential expression may return a non-empty XDM instance, but it never returns a non-empty pending update list.
[Definition: A simple expression is an expression that is neither an updating expression nor a sequential expression.] A simple expression may return an XDM instance, and it may construct a node or raise an error.
[Definition: A vacuous expression is a simple expression that can only return an empty sequence or raise an error.]
The classification of each expression into one of the above categories is performed by static analysis. For each kind of expression, XQSE provides rules that specify the required categories of the operand expressions and the category of the expression itself.
Note that simple expressions, updating expressions, and sequential expressions are disjoint categories, and that vacuous expressions are a subset of simple expressions. The kinds of values that can be returned by the various expression categories are summarized in the following table:
Expression category | Can return non-empty XDM instance? | Can return non-empty PUL? |
---|---|---|
Simple | YES | NO |
Updating | NO | YES |
Sequential | YES | NO |
Vacuous | NO | NO |
XQSEdefines an ordering on the evaluation of certain kinds of XQuery expressions. An implementation may use any execution strategy as long as the result complies with the semantics of this ordering. Since some of the expressions introduced by XQSE have immediate side effects, a well-defined evaluation order is necessary for a deterministic result.
XQSEsemantics are defined by the following evaluation order:
FLWOR:for, let, where, and order-by clauses are evaluated first, generating a tuple stream. Then the return clause is evaluated multiple times in the order of the tuple stream. If the return clause contains a sequential expression, the side effects of each iteration are visible to subsequent iterations.
Function calls:Argument expressions are evaluated before the function body.
If-then-else:The if-clause is evaluated first. Next, either the then-clause, or the else-clause (but not both), is evaluated.
Typeswitch:The switch-expression is evaluated first. Then, exactly one of the return-clauses is evaluated.
Concatenate (comma):Operand expressions are evaluated once, from left to right. Side effects of each sequential operand expression are visible to subsequent operand expressions.
Block:Variable declarations are evaluated first, in the order written; then the expressions in the body are evaluated, in the order written. The pending update list (if any) returned by each body expression is made effective before evaluation of the next body expression. XDM updates and side effects generated by each body expression are visible to subsequent body expressions.
While:The test expression is evaluated first. If its effective Boolean value is false, the body is not evaluated. If the effective Boolean value of the test expression is true, the body is evaluated repeatedly until the value of the test expression becomes false or until a break or exit expression is encountered. Side effects of each iteration are visible to subsequent iterations.
Note:
Since none of the XQuery expressions existing before XQSE has any immediate side-effects, no ordering is effectively imposed on the evaluation of any XQuery unless it contains one of the new expressions introduced by XQSE.
The term snapshot is defined in [XQuery Update Facility] as follows: [Definition: A
snapshot is a scope within which expressions are evaluated
with respect to a fixed XDM instance and updates are held pending.]
A snapshot is terminated by invocation of the
upd:applyUpdates
operation. Unlike XQUF, XQSE
permits a query to contain more than one snapshot. In XQSE, each expression within a block
constitutes a separate snapshot. If blocks are nested, snapshots
are defined by the innermost nested block.
Like [XQuery Update Facility], this
specification defines the semantics of operations on an XDM instance.
Propagation of changes to an underlying persistent store (if any)
is beyond the scope of this specification. Thus, for example, it is
implementation-defined whether the effects of an
fn:put
function are visible to an fn:doc
,
fn:doc-available
, or fn:collection
function executed in a subsequent snapshot.
[Definition: XQSEallows the keyword constant
to be
used in place of variable
in a Prolog declaration. A
variable declared in this way is called a constant.]
VarDecl ::= "declare" ("variable" | "constant") "$" QName TypeDeclaration? ((":=" ExprSingle) | "external")
Rules for initializing variables and for determining the scope of variables apply equally to constants. The semantics of constants are the same as the semantics of variables, with the following exception: It is a static error [err:TBD] if a constant appears on the left-hand-side of an assignment expression.
The initializing expression in a variable or constant declaration in a Prolog must be a simple expression [err:TBD].
FunctionDecl ::= "declare" "simple"? "function" QName "(" ParamList? ")" ("as" SequenceType)? (EnclosedExpr | "external") | "declare" "updating" "function" QName "(" ParamList? ")" (EnclosedExpr | "external") | "declare" "sequential" "function" QName "(" ParamList? ")" ("as" SequenceType)? (Block | "external")
[Definition: A simple function is a
function whose declaration specifies neither updating
nor sequential
.]
[Definition: An updating function
is a function whose declaration specifies the keyword
updating
.]
[Definition: A sequential
function is a function whose declaration specifies the keyword
sequential
.]
The EnclosedExpr in the body of a simple function (if any) must be a simple expression.
The EnclosedExpr in the body of an updating function (if any) must be an updating or vacuous expression.
The body of a sequential function (if any) is a Block, which is a sequential expression.
The semantics of simple functions are defined in [XQuery 1.0].
The semantics of updating functions are defined in [XQuery Update Facility].
The semantics of sequential functions are as follows:
If the body of a sequential function contains a Block, the result of the function is determined by the first exit expression encountered during evaluation of the Block. If no exit expression is encountered, the result of the function is an empty sequence.
If the result of a sequential function does not match
its declared result type (after applying function conversion rules
as specified in Section 3.1.5
Function CallsXQ), a type error is
raised [err:XPTY0004]. The default result type of a sequential
function is item()*
.
If a sequential function is declared
external
, its implementation is outside the XQuery
environment. The means by which parameters are passed to an
external function and its result is returned to the calling
expression are implementation-defined. An external sequential
function may not return a non-empty pending update list [err:TBD].
XQSEextends the XQuery 1.0 syntax by adding several new kinds of expressions. The effect of these new expressions on the XQuery grammar is as follows:
ExprSingle ::= (all existing options) | AssignmentExpr | Block | ExitExpr | WhileExpr | ContinueExpr | BreakExpr
AssignmentExpr ::= "set" "$" VarName ":=" ExprSingle
The expression on the right-hand-side of an assignment may not be an updating expression (it may be a simple expression or a sequential expression.)
An assignment expression is a sequential expression.
The variable on the left-hand side of the assignment must have been declared by a variable declaration, either in an enclosing block or in the Prolog, and it must be in scope [err:TBD].
Note:
Variables bound in FLWOR, typeswitch, or quantified expressions may not appear on the left-hand side of an assignment.
The expression on the right-hand side is evaluated. If the XDM instance returned by this expression does not match the declared type of the variable according to SequenceType matching rules, a type error is raised [err:TBD]. If the types match, the XDM instance returned by the expression is bound to the variable (added to variable values in the dynamic context.)
The result of an Assignment Expression is an empty XDM instance and an empty pending update list.
Block ::= "{" BlockDecls BlockBody "}" BlockDecls ::= (BlockVarDecl ";")* BlockVarDecl ::= "declare" "$" VarName TypeDeclaration? (":=" ExprSingle)? ("," "$" VarName TypeDeclaration? (":=" ExprSingle)? )* BlockBody ::= (Expr ";")*
The expressions on the right-hand-sides of block variable declarations must not be updating expressions.
Note:
Block variable declarations, unlike Prolog variable declarations, permit their initializing expressions to be sequential expressions.
The expressions in the body of the block may be in any category.
A block is a sequential expression.
A block consists of zero or more block variable declarations followed by a body. Each block variable declaration defines a local variable whose scope is the remainder of the block (not including its initializing expression). The variable defined in a block variable declaration occludes (hides) any variable of the same name that is in scope at the location where the block appears.
The block variable declarations are evaluated in the order written. [Definition: The expression on the right-hand side of a block variable declaration is called an initializing expression.] The block variable declaration evaluates its initializing expression and adds the resulting value to variable values in the dynamic context. If no initializing expression is present, the variable has no initial value. A reference to a variable, other than on the left-hand side of an assignment expression, is an error if the variable has no value in variable values when the reference is evaluated [err:TBD].
The type of each declared variable is added to in-scope
variables in the static context. If no explicit type
is declared, the type of the variable is inferred from the type of
its initializing expression. If the variable has neither an
explicit type declaration nor an initializing expression, its type
is item()*
. If a variable has both an explicit type
declaration and an initializing expression, the value of the
initializing expression must match the declared type according to
SequenceType matching rules; otherwise a type error is raised
[err:TBD].
It is a static error [err:TBD] if two or more variables declared in the same block have the same expanded QName.
After all the block variable declarations have been evaluated,
the body is evaluated. The body consists of one or more
expressions, separated by semicolons (the final expression may
optionally be followed by a semicolon.) The expressions in the body
are evaluated in the order they appear. After the evaluation of
each expression, the pending update list returned by the expression (if
any) is applied (by upd:applyUpdates
), and the
XDM instance
returned by the expression (if any) is discarded. The side effects
of each expression are visible during the evaluation of subsequent
expressions.
The result of a block is an empty XDM instance and an empty pending update list.
ExitExpr ::= "exit" "with" ExprSingle
The operand of an exit expression must not be an updating expression.
If an exit expression is in the body of a function declaration,
that function declaration must not specify updating
[err:TBD].
An exit expression is a sequential expression.
An exit expression serves to define the result of the enclosing function or query body.
If an exit expression is evaluated within the body of a function, further evaluation of the function body is interrupted and the XDM instance returned by the operand expression is returned as the result of the function call.
If an exit expression is evaluated within a query body (i.e., not within the body of a function), further evaluation of the query is interrupted and the XDM instance returned by the operand expression is returned as the result of the query.
Note:
An exit expression in a block terminates evaluation of the enclosing function body or query, not just the immediately enclosing block.
WhileExpr ::= "while" "(" ExprSingle ")" Block
The expression enclosed in parentheses, called the test expression, may not be an updating expression.
A while expression is a sequential expression.
The while expression is used for conditional iteration. It is evaluated as follows:
First, the test expression is evaluated. If its effective Boolean value is false, the block is not evaluated. If the effective Boolean value of the test expression is true, the block is evaluated repeatedly. Each evaluation of the block may cause side effects that affect the test expression. The test expression is evaluated after each evaluation of the block. This process continues until the effective Boolean value of the test expression is evaluated to be false or until a break or exit expression is evaluated within the block.
The result of a while expression is an empty XDM instance and an empty pending update list.
In the following block, a while expression is used to compute a sequence containing all the Fibonacci numbers that are less than 100.
{ declare $a as xs:integer := 0; declare $b as xs:integer := 1; declare $c as xs:integer := $a + $b; declare $fibseq as xs:integer* := ($a, $b); while ($c < 100) { set $fibseq := ($figseq, $c); set $a := $b; set $b := $c; set $c := $a + $b; }; exit with $fibseq; }
ContinueExpr ::= "continue" "loop" BreakExpr ::= "break" "loop"
Continue and break expressions are sequential expression.
Continue and break expressions provide convenient ways to control the evaluation of a while expression.
If a continue expression is evaluated, it interrupts the current iteration of the nearest enclosing while expression, and starts the next iteration.
If a break expression is evaluated, it halts the evaluation of the nearest enclosing while expression.
If a continue or break expression has no enclosing while expression, a static error is raised [err:TBD].
Note:
Continue and break expressions have no effect on evaluation of a FLWOR expression, even if they are contained in the return-clause of the FLWOR.
Since this proposal introduces a new category of expression (sequential expression), the existing expressions need to specify whether they accept expressions in the new category as operands. In some cases, the category of an expression is determined by the categories of its operands.
The parameters of a function call must be simple expressions.
A call to the built-in function fn:error
is a
vacuous
expression.
A call to an updating function is an updating expression.
A call to a sequential function is a sequential expression.
A call to any other function is a simple expression.
The for
, let
, where
, and
order by
clauses must contain simple
expressions.
The return
clause may contain any kind of
expression.
The category of the FLWOR expression is the same as the category
of the expression in its return
clause.
The result of a FLWOR expression is the concatenation of the
XDM instances
or pending update
lists returned by successive evaluations of the
return
clause, in evaluation order. Pending update lists are
concatenated by the upd:mergeUpdates
operation.
The expression in the if
clause must be a simple
expression.
Let the expressions in the then
and
else
clauses be called branches. Then:
If one branch is an updating expression, the other branch must be an updating expression or a vacuous expression. In this case, the conditional expression is an updating expression.
If one branch is a sequential expression, the other branch must be a sequential expression or a simple expression. In this case, the conditional expression is a sequential expression.
If both branches are vacuous expressions, the conditional expression is a vacuous expression.
Otherwise, the conditional expression is a simple expression.
The expression following the typeswitch
keyword
must be a simple expression.
Let the expressions in the case
and
default
clauses be called branches. Then:
If any branch is an updating expression, then all branches must be updating or vacuous expressions. In this case, the typeswitch expression is an updating expression.
If any branch is a sequential expression, then all branches must be sequential or simple expressions. In this case, the typeswitch expression is a sequential expression.
If all branches are vacuous expressions, the typeswitch expression is a vacuous expression.
Otherwise, the typeswitch expression is a simple expression.
The category of a comma expression is determined by the following rules:
If any operand is an updating expression, then all operands must be updating or vacuous expressions. In this case, the comma expression is an updating expression.
If any operand is a sequential expression, then all operands must be sequential or simple expressions. In this case, the comma expression is a sequential expression.
If all operands are vacuous expressions, the comma expression is a vacuous expression.
Otherwise, the comma expression is a simple expression.
Any category of expression may be enclosed in parentheses; the
resulting expression has the same category as the original
expression. An empty parenthesized expression ( )
is a
vacuous
expression.
The operand of an ordered or unordered expression may be an expression of any category. The category of the ordered or unordered expression is the same as the category of its operand.
The copy
clause must contain a simple
expression.
The modify
clause must contain an updating or
vacuous
expression.
The return
clause must contain a simple or sequential
expression.
The category of the transform expression is the same as the
category of its return
clause.
The operand of an extension expression may be an expression of any category. The category of the extension expression is the same as the category of its operand.
All expressions not listed above are simple expressions, and accept only simple expressions as their operands. This includes the following kinds of expressions:
Path expressions
Filter expressions
Range expressions
Union, intersect, and except expressions
Arithmetic, comparison, and logical expressions
Constructors of all kinds
Ordered and unordered expressions
Quantified expressions
Instance of, cast, castable, and treat expressions
Validate expressions
The following function returns true
or
false
according to whether its parameter is a known
user name, and logs the event:
declare sequential function validate-and-log($username as xs:string) as xs:boolean { declare $log as document-node() := fn:doc("log.xml"); declare $entry as element() := <access-attempt> <timestamp>{fn:current-dateTime()}</timestamp> <user-name>{$username}</user-name> <access-allowed/> </access-attempt> ; declare $result as xs:boolean; if ($username = doc("users.xml")/current-users/user/name ) then { replace value of node $entry/access-allowed with "Yes"; set $result := true(); } else { replace value of node $entry/access-allowed with "No"; set $result := false(); } ; insert node $entry as last into $log; fn:put($log, "log.xml"); exit with $result; }
VarDecl ::= "declare" ("variable" | "constant") "$" QName TypeDeclaration? ((":=" ExprSingle) | "external") ExprSingle ::= (all existing options) | AssignmentExpr | Block | ExitExpr | WhileExpr | ContinueExpr | BreakExpr AssignmentExpr ::= "set" "$" VarName ":=" ExprSingle Block ::= "{" BlockDecls BlockBody "}" BlockDecls ::= (BlockVarDecl ";")* BlockVarDecl ::= "declare" "$" VarName TypeDeclaration? (":=" ExprSingle)? ("," "$" VarName TypeDeclaration? (":=" ExprSingle)? )* BlockBody ::= (Expr ";")* ExitExpr ::= "exit" "with" ExprSingle WhileExpr ::= "while" "(" ExprSingle ")" Block ContinueExpr ::= "continue" "loop" BreakExpr ::= "break" "loop" FunctionDecl ::= "declare" "simple"? "function" QName "(" ParamList? ")" ("as" SequenceType)? (EnclosedExpr | "external") | "declare" "updating" "function" QName "(" ParamList? ")" (EnclosedExpr | "external") | "declare" "sequential" "function" QName "(" ParamList? ")" ("as" SequenceType)? (Block | "external")
[XML Syntax for XQuery 1.0] defines an XML representation of [XQuery 1.0]. [XQuery Scripting Requirements] states "The syntax for updates MAY have more than one syntax binding. One syntax MUST be convenient for humans to read and write. One syntax MUST be expressed in XML in a way that reflects the underlying structure of the operations." This appendix specifies an XML Schema that defines the XML representation of XQuery Scripting Extension 1.0 by representing the abstract syntax found in A Summary of XQSE Grammar Changes. This XML representation for XQuery Scripting Extension 1.0 integrates with the XML representation for XQuery 1.0 and that for the XQuery Update Facility 1.0.
The XML Schema specified in this appendix accomplishes its integration by importing the XML Schema defined for XQueryX in [XQuery Update Facility], incorporating all of its type and element definitions. It then extends that schema by adding definitions of new types and elements in a namespace belonging to the XQuery Scripting Extension 1.0 specification.
This section specifies the XML Schema that defines the complex types and elements for XQueryX in support of XQuery Scripting Extension 1.0, including changes to the prolog and the addition of several new expressions. It also specifies a second XML Schema that redefines an element defined in XQueryX 1.0. Copies of these two schemata can be found at http://www.w3.org/2008/xquery-sx-10/xquery-sx-10-xqueryx.xsd. and http://www.w3.org/2008/xquery-sx-10/xquery-sx-10-xqueryx-redef.xsd. Please note that the content of these schemata are subject to change at any time before this document is published as a Recommendation.
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xqx="http://www.w3.org/2005/XQueryX" xmlns:xqxuf="http://www.w3.org/2007/xquery-update-10" xmlns:xqxsx="http://www.w3.org/2008/xquery-sx-10" targetNamespace="http://www.w3.org/2008/xquery-sx-10" elementFormDefault="qualified" attributeFormDefault="unqualified"> <!-- Initial creation 2008-03-01: Jim Melton --> <!-- Added FunctionDecl redefinition 2008-03-11: Jim Melton --> <xsd:import namespace="http://www.w3.org/2005/XQueryX" schemaLocation="http://www.w3.org/2008/xquery-sx-10/xquery-sx-10-xqueryx-redef.xsd"/> <!-- Declare new type for constant declarations --> <xsd:complexType name="constDecl"> <xsd:sequence> <xsd:element name="constName" type="xqx:QName"/> <xsd:element ref="xqx:typeDeclaration" minOccurs="0"/> <xsd:element name="constValue" type="xqx:exprWrapper"/> </xsd:sequence> </xsd:complexType> <xsd:element name="constDecl" type="xqxsx:constDecl" substitutionGroup="xqx:prologPartTwoItem"/> <!-- Create substitution grp for scripting extension exprs --> <xsd:complexType name="expr"> <xsd:complexContent> <xsd:extension base="xqx:expr"/> </xsd:complexContent> </xsd:complexType> <!-- Make scripting extension subst grp part of expr grp --> <xsd:element name="expr" type="xqxsx:expr" abstract="true" substitutionGroup="xqx:expr"/> <!-- AssignmentExpr: --> <!-- AssignmentExpr ::= "set" "$" VarName ":=" ExprSingle --> <xsd:complexType name="assignmentExpr"> <xsd:complexContent> <xsd:extension base="xqxsx:expr"> <xsd:sequence> <xsd:element ref="xqx:positionalVariableBinding"/> <xsd:element name="assignedExpr" type="xqx:exprWrapper"/> </xsd:sequence> </xsd:extension> </xsd:complexContent> </xsd:complexType> <xsd:element name="assignmentExpr" type="xqxsx:assignmentExpr" substitutionGroup="xqxsx:expr"/> <!-- Block (1 of 3): --> <!-- Block ::= "{" BlockDecls BlockBody "}" --> <!-- BlockDecls ::= (BlockVarDecl ";")* --> <xsd:complexType name="block"> <xsd:complexContent> <xsd:extension base="xqxsx:expr"> <xsd:sequence> <xsd:element ref="xqxsx:blockVarDecl" minOccurs="0" maxOccurs="unbounded"/> <xsd:element ref="xqxsx:blockBody"/> </xsd:sequence> </xsd:extension> </xsd:complexContent> </xsd:complexType> <xsd:element name="block" type="xqxsx:block" substitutionGroup="xqxsx:expr"/> <!-- Block (2 of 3): --> <!-- BlockVarDecl ::= --> <!-- "declare" "$" VarName TypeDeclaration? --> <!-- (":=" ExprSingle)? --> <!-- ("," "$" VarName TypeDeclaration? --> <!-- (":=" ExprSingle)? )* --> <xsd:complexType name="blockVarDecl"> <xsd:sequence minOccurs="1" maxOccurs="unbounded"> <xsd:element name="varName" type="xqx:QName"/> <xsd:element ref="xqx:typeDeclaration" minOccurs="0"/> <xsd:element name="varValue" type="xqx:exprWrapper" minOccurs="0"/> </xsd:sequence> </xsd:complexType> <xsd:element name="blockVarDecl" type="xqxsx:blockVarDecl"/> <!-- Block (3 of 3): --> <!-- BlockBody ::= (Expr ";")* --> <xsd:complexType name="blockBody"> <xsd:sequence> <xsd:element name="blockExpr" type="xqx:exprWrapper" minOccurs="1" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> <xsd:element name="blockBody" type="xqxsx:blockBody"/> <!-- ExitExpr: --> <!-- ExitExpr ::= "exit" "with" ExprSingle --> <xsd:element name="exitExpr" type="xqxsx:expr" substitutionGroup="xqxsx:expr"/> <!-- WhileExpr: --> <!-- WhileExpr ::= "while" "(" ExprSingle ")" Block --> <xsd:complexType name="whileExpr"> <xsd:complexContent> <xsd:extension base="xqxsx:expr"> <xsd:sequence> <xsd:element name="whileTest" type="xqx:exprWrapper"/> <xsd:element ref="xqxsx:block"/> </xsd:sequence> </xsd:extension> </xsd:complexContent> </xsd:complexType> <xsd:element name="whileExpr" type="xqxsx:whileExpr" substitutionGroup="xqxsx:expr"/> <!-- ContinueExpr: --> <!-- ContinueExpr ::= "continue" "loop" --> <xsd:complexType name="continueExpr"> <xsd:complexContent> <xsd:restriction base="xqxsx:expr"/> </xsd:complexContent> </xsd:complexType> <xsd:element name="continueExpr" type="xqxsx:continueExpr" substitutionGroup="xqxsx:expr"/> <!-- BreakExpr: --> <!-- BreakExpr ::= "break" "loop" --> <xsd:complexType name="breakExpr"> <xsd:complexContent> <xsd:restriction base="xqxsx:expr"/> </xsd:complexContent> </xsd:complexType> <xsd:element name="breakExpr" type="xqxsx:breakExpr" substitutionGroup="xqxsx:expr"/> </xsd:schema> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/2005/XQueryX" targetNamespace="http://www.w3.org/2005/XQueryX" elementFormDefault="qualified" attributeFormDefault="qualified"> <!-- Redefine one or more components of the XQueryX XML Schema --> <!-- The redefinition starts with XQuery Update Facility 1.0 --> <!-- XQueryX instead of XQueryX 1.0 --> <xsd:redefine schemaLocation="http://www.w3.org/2007/xquery-update-10/xquery-update-10-xqueryx-redef.xsd"> <!-- Redefine the functionDecl complex type --> <xsd:complexType name="functionDecl"> <xsd:complexContent> <xsd:extension base="functionDecl"> <xsd:attribute name="simpleFunction" type="xsd:boolean" default="true"/> <xsd:attribute name="sequentialFunction" type="xsd:boolean" default="false"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> </xsd:redefine> </xsd:schema>
This section specifies the XSLT stylesheet that defines the semantics of XQueryX in support of XQuery Scripting Extension 1.0. It imports the XSLT stylesheet defined in [XQuery Update Facility], and provides additional templates that define the semantics of the XQueryX representation of XQuery Scripting Extension 1.0 by transforming that XQueryX representation into the human readable syntax of XQuery Scripting Extension 1.0. A copy of this stylesheet is located at http://www.w3.org/2008/xquery-sx-10/xquery-sx-10-xqueryx.xsl. Please note that the content of this stylesheet is subject to change at any time before this document is published as a Recommendation.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xqx="http://www.w3.org/2005/XQueryX" xmlns:xqxuf="http://www.w3.org/2007/xquery-update-10" xmlns:xqxsx="http://www.w3.org/2008/xquery-sx-10"> <!-- Initial creation 2008-03-01: Jim Melton --> <xsl:import href="http://www.w3.org/2007/xquery-update-10/xquery-update-10-xqueryx.xsl"/> <!-- constDecl --> <xsl:template match="xqxsx:constDecl"> <xsl:value-of select="$NEWLINE"/> <xsl:text>declare constant </xsl:text> <xsl:apply-templates/> </xsl:template> <xsl:template match="xqxsx:constName"> <xsl:apply-templates/> </xsl:template> <xsl:template match="xqxsx:constValue"> <xsl:apply-templates/> </xsl:template> <!-- assignmentExpr --> <xsl:template match="xqxsx:assignmentExpr"> <xsl:value-of select="$NEWLINE"/> <xsl:text>set </xsl:text> <xsl:apply-templates select="xqx:positionalVariableBinding"/> <xsl:text> := </xsl:text> <xsl:apply-templates/> </xsl:template> <xsl:template match="xqxsx:assignedExpr"> <xsl:apply-templates/> </xsl:template> <!-- block --> <xsl:template match="xqxsx:block"> <xsl:value-of select="$NEWLINE"/> <xsl:value-of select="$LBRACE"/> <xsl:value-of select="$SPACE"/> <xsl:apply-templates/> <xsl:value-of select="$SPACE"/> <xsl:value-of select="$RBRACE"/> <xsl:value-of select="$SPACE"/> </xsl:template> <!-- blockVarDecl --> <xsl:template match="xqxsx:blockVarDecl[position()=1 and position()=last()]"> <xsl:text>declare </xsl:text> <xsl:apply-templates select="xqxsx:varName"/> <xsl:if test="xqx:typeDeclaration"> <xsl:apply-templates select="xqx:typeDeclaration"/> </xsl:if> <xsl:if test="xqxsx:varValue"> <xsl:text> := </xsl:text> <xsl:apply-templates select="xqxsx:varValue"/> </xsl:if> <xsl:value-of select="$SEMICOLON"/> </xsl:template> <xsl:template match="xqxsx:blockVarDecl[position()=1 and position()!=last()]"> <xsl:text>declare </xsl:text> <xsl:apply-templates select="xqxsx:varName"/> <xsl:if test="xqx:typeDeclaration"> <xsl:apply-templates select="xqx:typeDeclaration"/> </xsl:if> <xsl:if test="xqxsx:varValue"> <xsl:text> := </xsl:text> <xsl:apply-templates select="xqxsx:varValue"/> </xsl:if> </xsl:template> <xsl:template match="xqxsx:blockVarDecl[position()>1 and position()<last()]"> <xsl:value-of select="$COMMA"/> <xsl:value-of select="$NEWLINE"/> <xsl:apply-templates select="xqxsx:varName"/> <xsl:if test="xqx:typeDeclaration"> <xsl:apply-templates select="xqx:typeDeclaration"/> </xsl:if> <xsl:if test="xqxsx:varValue"> <xsl:text> := </xsl:text> <xsl:apply-templates select="xqxsx:varValue"/> </xsl:if> </xsl:template> <xsl:template match="xqxsx:blockVarDecl[position()>1 and position()=last()]"> <xsl:value-of select="$COMMA"/> <xsl:value-of select="$NEWLINE"/> <xsl:apply-templates select="xqxsx:varName"/> <xsl:if test="xqx:typeDeclaration"> <xsl:apply-templates select="xqx:typeDeclaration"/> </xsl:if> <xsl:if test="xqxsx:varValue"> <xsl:text> := </xsl:text> <xsl:apply-templates select="xqxsx:varValue"/> </xsl:if> <xsl:value-of select="$SEMICOLON"/> </xsl:template> <xsl:template match="xqxsx:varName"> <xsl:apply-templates/> </xsl:template> <xsl:template match="xqxsx:varValue"> <xsl:apply-templates/> </xsl:template> <!-- blockBody --> <xsl:template match="xqxsx:blockBody"> <xsl:apply-templates/> </xsl:template> <xsl:template match="xqxsx:blockExpr"> <xsl:apply-templates/> <xsl:value-of select="$SEMICOLON"/> </xsl:template> <!-- exitExpr --> <xsl:template match="xqxsx:exitExpr"> <xsl:value-of select="$NEWLINE"/> <xsl:text>exit with </xsl:text> <xsl:apply-templates/> </xsl:template> <!-- whileExpr --> <xsl:template match="xqxsx:whileExpr"> <xsl:value-of select="$NEWLINE"/> <xsl:text>while </xsl:text> <xsl:value-of select="$LPAREN"/> <xsl:value-of select="$SPACE"/> <xsl:apply-templates select="xqxsx:whileTest"/> <xsl:value-of select="$SPACE"/> <xsl:value-of select="$RPAREN"/> <xsl:value-of select="$NEWLINE"/> <xsl:apply-templates select="xqxsx:block"/> <xsl:value-of select="$NEWLINE"/> </xsl:template> <xsl:template match="xqxsx:whileTest"> <xsl:apply-templates/> </xsl:template> <!-- continueExpr --> <xsl:template match="xqxsx:continueExpr"> <xsl:value-of select="$NEWLINE"/> <xsl:text>continue loop </xsl:text> </xsl:template> <!-- breakExpr --> <xsl:template match="xqxsx:breakExpr"> <xsl:value-of select="$NEWLINE"/> <xsl:text>break loop </xsl:text> </xsl:template> <!-- Over-ride the template for functionDecl in XQuery --> <!-- Update Facility xquery-update-10-xqueryx-redef.xsd --> <xsl:template match="xqx:functionDecl" priority="200"> <xsl:text>declare </xsl:text> <xsl:choose> <xsl:when test="@xqx:updatingFunction and @xqx:updatingFunction = 'true'"> <xsl:text>updating </xsl:text> </xsl:when> <xsl:when test="@xqx:sequentialFunction and @xqx:sequentialFunction = 'true'"> <xsl:text>sequential </xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>simple </xsl:text> </xsl:otherwise> </xsl:choose> <xsl:text>function </xsl:text> <xsl:apply-templates select="xqx:functionName"/> <xsl:apply-templates select="xqx:paramList"/> <xsl:apply-templates select="xqx:typeDeclaration"/> <xsl:apply-templates select="xqx:functionBody"/> <xsl:if test="xqx:externalDefinition"> <xsl:text> external </xsl:text> </xsl:if> </xsl:template> </xsl:stylesheet>
The following example is based on the data and queries in the use cases in [XQuery Scripting Use Cases]. In this example, we show the English description of the query, the XQuery Scripting Extension solution given in [XQuery Scripting Use Cases], an XQueryX solution, and the XQuery Update Facility expression that results from applying the Update Facility XQueryX-to-XQuery Update Facility transformation defined by the stylesheet in B.2 Stylesheet to the Scripting Extension XQueryX solution. The XQuery Scripting Extension expression that is produced is presented only as a sanity-check—the intent of the stylesheet is not to recreate the original XQuery expression, but to produce a valid XQuery expression with the same semantics. The semantics of the Scripting Extension XQueryX solution are determined by the semantics of the XQuery Update Facility expression that results from that transformation. The "correctness" of that transformation is determined by asking the following the question: Can some Scripting Extension XQueryX processor QX process some Scripting Extension XQueryX document D1 to produce results R1, after which the stylesheet is used to translate D1 into an XQuery Scripting Extension expression E1 that, when processed by some XQuery Scripting Extension processor Q, produces results R2 that are equivalent (under some meaningful definition of "equivalent") to results R1?
Comparison of the results of the Scripting Extension XQueryX-to-XQuery Scripting Extension transformation given in this document with the XQuery Scripting Extension solutions in [XQuery Scripting Use Cases] may be helpful in evaluating the correctness of the Update Facility XQueryX solution in each example.
The XQuery Scripting Extension Use Cases solution given for each example is provided only to assist readers of this document in understanding the Scripting Extension XQueryX solution. There is no intent to imply that this document specifies a "compilation" or "transformation" of XQuery Scripting Extension syntax into Scripting Extension XQueryX syntax.
In the following example, note that path expressions are expanded to show their structure. Also, note that the prefix syntax for binary operators like "and" makes the precedence explicit. In general, humans find it easier to read an XML representation that does not expand path expressions, but it is less convenient for programmatic representation and manipulation. XQueryX is designed as a language that is convenient for production and modification by software, and not as a convenient syntax for humans to read and write.
Finally, please note that white space, including new lines, have been added to some of the Scripting Extension XQueryX documents and XQuery Scripting Extension expressions for readability. That additional white space is not produced by the Scripting Extension XQueryX-to-XQuery Scripting Extension transformation.
This example is based on query "Q2" from [XQuery Scripting Use Cases], use case "R": "Scripting Relational Data":
let $uid := doc("users.xml")/users/user_tuple[name = "Roger Smith"]/userid let $topbid := max(doc("bids.xml")/bids/bid_tuple[itemno = 1007]/bid) let $newbid := $topbid * 1.1 return if($newbid <= 240) then { insert nodes <bid_tuple> <userid>{ data($uid) }</userid> <itemno>1002</itemno> <bid>{ $newbid }</bid> <bid_date>1999-03-03</bid_date> </bid_tuple> into doc("bids.xml")/bids; exit with <new_bid>{ $newbid }</new_bid>; } else { exit with <top_bid>{ $topbid }</top_bid>; }
<!-- let $uid := doc("users.xml")/users/user_tuple[name = "Roger Smith"]/userid let $topbid := max(doc("bids.xml")/bids/bid_tuple[itemno = 1007]/bid) let $newbid := $topbid * 1.1 return if($newbid <= 240) then { insert nodes <bid_tuple> <userid>{ data($uid) }</userid> <itemno>1002</itemno> <bid>{ $newbid }</bid> <bid_date>1999-03-03</bid_date> </bid_tuple> into doc("bids.xml")/bids; exit with <new_bid>{ $newbid }</new_bid>; } else { exit with <top_bid>{ $topbid }</top_bid>; } --> <xqx:module xmlns:xqx="http://www.w3.org/2005/XQueryX" xmlns:xqxuf="http://www.w3.org/2007/xquery-update-10" xmlns:xqxsx="http://www.w3.org/2008/xquery-sx-10" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3.org/2005/XQueryX http://www.w3.org/2005/XQueryX/xqueryx.xsd http://www.w3.org/2007/xquery-update-10 http://www.w3.org/2007/xquery-update-10/xquery-update-10-xqueryx.xsd http://www.w3.org/2008/xquery-sx-10 http://www.w3.org/2008/xquery-sx-10/xquery-sx-10-xqueryx.xsd"> <xqx:queryBody> <xqx:flworExpr> <!-- let $uid := doc("users.xml")/users/user_tuple[name = "Roger Smith"]/userid --> <xqx:letClause> <xqx:letClauseItem> <xqx:typedVariableBinding> <xqx:varName>uid</xqx:varName> </xqx:typedVariableBinding> <xqx:letExpr> <xqx:pathExpr> <xqx:stepExpr> <xqx:filterExpr> <xqx:functionCallExpr> <xqx:functionName xqx:prefix="fn">doc</xqx:functionName> <xqx:arguments> <xqx:stringConstantExpr> <xqx:value>users.xml</xqx:value> </xqx:stringConstantExpr> </xqx:arguments> </xqx:functionCallExpr> </xqx:filterExpr> </xqx:stepExpr> <xqx:stepExpr> <xqx:xpathAxis>child</xqx:xpathAxis> <xqx:nameTest>users</xqx:nameTest> </xqx:stepExpr> <xqx:stepExpr> <xqx:xpathAxis>child</xqx:xpathAxis> <xqx:nameTest>user-tuple</xqx:nameTest> <xqx:predicates> <xqx:equalOp> <xqx:firstOperand> <xqx:pathExpr> <xqx:stepExpr> <xqx:xpathAxis>child</xqx:xpathAxis> <xqx:nameTest>name</xqx:nameTest> </xqx:stepExpr> </xqx:pathExpr> </xqx:firstOperand> <xqx:secondOperand> <xqx:stringConstantExpr> <xqx:value>Roger Smith</xqx:value> </xqx:stringConstantExpr> </xqx:secondOperand> </xqx:equalOp> </xqx:predicates> </xqx:stepExpr> <xqx:stepExpr> <xqx:xpathAxis>child</xqx:xpathAxis> <xqx:nameTest>userid</xqx:nameTest> </xqx:stepExpr> </xqx:pathExpr> </xqx:letExpr> </xqx:letClauseItem> </xqx:letClause> <!-- let $topbid := max(doc("bids.xml")/bids/bid_tuple[itemno = 1007]/bid) --> <xqx:letClause> <xqx:letClauseItem> <xqx:typedVariableBinding> <xqx:varName>topbid</xqx:varName> </xqx:typedVariableBinding> <xqx:letExpr> <xqx:pathExpr> <xqx:stepExpr> <xqx:filterExpr> <xqx:functionCallExpr> <xqx:functionName xqx:prefix="fn">max</xqx:functionName> <xqx:arguments> <xqx:pathExpr> <xqx:stepExpr> <xqx:filterExpr> <xqx:functionCallExpr> <xqx:functionName xqx:prefix="fn">doc</xqx:functionName> <xqx:arguments> <xqx:stringConstantExpr> <xqx:value>bids.xml</xqx:value> </xqx:stringConstantExpr> </xqx:arguments> </xqx:functionCallExpr> </xqx:filterExpr> </xqx:stepExpr> <xqx:stepExpr> <xqx:xpathAxis>child</xqx:xpathAxis> <xqx:nameTest>bids</xqx:nameTest> </xqx:stepExpr> <xqx:stepExpr> <xqx:xpathAxis>child</xqx:xpathAxis> <xqx:nameTest>bid-tuple</xqx:nameTest> <xqx:predicates> <xqx:equalOp> <xqx:firstOperand> <xqx:pathExpr> <xqx:stepExpr> <xqx:xpathAxis>child</xqx:xpathAxis> <xqx:nameTest>itemno</xqx:nameTest> </xqx:stepExpr> </xqx:pathExpr> </xqx:firstOperand> <xqx:secondOperand> <xqx:integerConstantExpr> <xqx:value>1007</xqx:value> </xqx:integerConstantExpr> </xqx:secondOperand> </xqx:equalOp> </xqx:predicates> </xqx:stepExpr> <xqx:stepExpr> <xqx:xpathAxis>child</xqx:xpathAxis> <xqx:nameTest>bid</xqx:nameTest> </xqx:stepExpr> </xqx:pathExpr> </xqx:arguments> </xqx:functionCallExpr> </xqx:filterExpr> </xqx:stepExpr> </xqx:pathExpr> </xqx:letExpr> </xqx:letClauseItem> </xqx:letClause> <!-- let $newbid := $topbid * 1.1 --> <xqx:letClause> <xqx:letClauseItem> <xqx:typedVariableBinding> <xqx:varName>newbid</xqx:varName> </xqx:typedVariableBinding> <xqx:letExpr> <xqx:multiplyOp> <xqx:firstOperand> <xqx:varRef> <xqx:name>topbid</xqx:name> </xqx:varRef> </xqx:firstOperand> <xqx:secondOperand> <xqx:decimalConstantExpr> <xqx:value>1.1</xqx:value> </xqx:decimalConstantExpr> </xqx:secondOperand> </xqx:multiplyOp> </xqx:letExpr> </xqx:letClauseItem> </xqx:letClause> <!-- return --> <xqx:returnClause> <!-- if($newbid <= 240) --> <xqx:ifThenElseExpr> <xqx:ifClause> <xqx:lessThanOrEqualOp> <xqx:firstOperand> <xqx:varRef> <xqx:name>newbid</xqx:name> </xqx:varRef> </xqx:firstOperand> <xqx:secondOperand> <xqx:integerConstantExpr> <xqx:value>240</xqx:value> </xqx:integerConstantExpr> </xqx:secondOperand> </xqx:lessThanOrEqualOp> </xqx:ifClause> <!-- then { --> <xqx:thenClause> <xqxsx:block> <xqxsx:blockBody> <xqxsx:blockExpr> <!-- insert nodes --> <xqxuf:insertExpr> <xqxuf:sourceExpr> <!-- <bid_tuple> --> <xqx:elementConstructor> <xqx:tagName>bid_tuple</xqx:tagName> <xqx:elementContent> <!-- <userid>{ data($uid) }</userid> --> <xqx:elementConstructor> <xqx:tagName>userid</xqx:tagName> <xqx:elementContent> <xqx:functionCallExpr> <xqx:functionName xqx:prefix="fn">data</xqx:functionName> <xqx:arguments> <xqx:exprList> <xqx:expr> <xqx:varRef> <xqx:name>uid</xqx:name> </xqx:varRef> </xqx:expr> </xqx:exprList> </xqx:arguments> </xqx:functionCallExpr> </xqx:elementContent> </xqx:elementConstructor> <!-- <itemno>1002</itemno> --> <xqx:elementConstructor> <xqx:tagName>itemno</xqx:tagName> <xqx:elementContent> <xqx:integerConstantExpr> <xqx:value>1002</xqx:value> </xqx:integerConstantExpr> </xqx:elementContent> </xqx:elementConstructor> <!-- <bid>{ $newbid }</bid> --> <xqx:elementConstructor> <xqx:tagName>bid</xqx:tagName> <xqx:elementContent> <xqx:varRef> <xqx:name>bid</xqx:name> </xqx:varRef> </xqx:elementContent> </xqx:elementConstructor> <!-- <bid_date>1999-03-03</bid_date> --> <xqx:elementConstructor> <xqx:tagName>bid_date</xqx:tagName> <xqx:elementContent> <xqx:stringConstantExpr> <xqx:value>1999-03-03</xqx:value> </xqx:stringConstantExpr> </xqx:elementContent> </xqx:elementConstructor> </xqx:elementContent> </xqx:elementConstructor> </xqxuf:sourceExpr> <!-- into doc("bids.xml")/bids; --> <xqxuf:insertInto/> <xqxuf:targetExpr> <xqx:pathExpr> <xqx:stepExpr> <xqx:filterExpr> <xqx:functionCallExpr> <xqx:functionName xqx:prefix="fn">doc</xqx:functionName> <xqx:arguments> <xqx:stringConstantExpr> <xqx:value>bids.xml</xqx:value> </xqx:stringConstantExpr> </xqx:arguments> </xqx:functionCallExpr> </xqx:filterExpr> </xqx:stepExpr> <xqx:stepExpr> <xqx:xpathAxis>child</xqx:xpathAxis> <xqx:nameTest>bids</xqx:nameTest> </xqx:stepExpr> </xqx:pathExpr> </xqxuf:targetExpr> </xqxuf:insertExpr> </xqxsx:blockExpr> <!-- exit with <new_bid>{ $newbid }</new_bid>; --> <xqxsx:blockExpr> <xqxsx:exitExpr> <xqx:elementConstructor> <xqx:tagName>new_bid</xqx:tagName> <xqx:elementContent> <xqx:varRef> <xqx:name>newbid</xqx:name> </xqx:varRef> </xqx:elementContent> </xqx:elementConstructor> </xqxsx:exitExpr> </xqxsx:blockExpr> <xqxsx:termSemicolon/> </xqxsx:blockBody> </xqxsx:block> </xqx:thenClause> <!-- } else { --> <xqx:elseClause> <!-- exit with <top_bid>{ $topbid }</top_bid>; --> <xqxsx:block> <xqxsx:blockBody> <xqxsx:blockExpr> <xqxsx:exitExpr> <xqx:elementConstructor> <xqx:tagName>top_bid</xqx:tagName> <xqx:elementContent> <xqx:varRef> <xqx:name>topbid</xqx:name> </xqx:varRef> </xqx:elementContent> </xqx:elementConstructor> </xqxsx:exitExpr> </xqxsx:blockExpr> <xqxsx:termSemicolon/> </xqxsx:blockBody> </xqxsx:block> </xqx:elseClause> </xqx:ifThenElseExpr> </xqx:returnClause> <!-- } --> </xqx:flworExpr> </xqx:queryBody> </xqx:module>
Application of the stylesheet in B.2 Stylesheet to the Update Facility XQueryX representation results in the following XQuery representation:
( let $uid:=fn:doc("users.xml")/child::users/ child::user-tuple[(child::name = "Roger Smith")]/child::userid let $topbid:=fn:max(fn:doc("bids.xml")/child::bids/ child::bid-tuple[(child::itemno = 1007)]/child::bid) let $newbid:=($topbid*1.1) return ( if (($newbid <= 240)) then { insert nodes <bid_tuple><userid>{fn:data($uid)}</userid> <itemno>{1002}</itemno> <bid>{$bid}</bid> <bid_date>{"1999-03-03"}</bid_date></bid_tuple> into fn:doc("bids.xml")/child::bids; exit with <new_bid>{$newbid}</new_bid>; } else { exit with <top_bid>{$topbid}</top_bid>; } ) )
The following items in this specification are implementation-defined:
The effects of snapshot
semantics on persistent storage. For example, it is
implementation-defined whether the effects of an
fn:put
function are visible to an fn:doc
,
fn:doc-available
, or fn:collection
function executed in a subsequent snapshot.
The mechanism (if any) by which the XQuery environment exchanges parameters and results with an external function.
The following are some issues that are under discussion in the working group:
Semantics of break and continue:
Break and continue expressions are currently defined to affect the nearest enclosing while-loop. Alternatively, they could be defined to affect the nearest enclosing FLWOR or while-loop.
If break and continue expressions were defined to affect FLWOR expressions, the semantics of FLWOR would become more complex. Currently, the return-clause values for all iterations are concatenated to form the result of a FLWOR. If an iteration is terminated by a break or continue, we would need to define which XDM values from that iteration are retained as part of the FLWOR-result, and which of the side-effects from that iteration are made effective. For example:
Should this example return ("a", "a")
or
()
?
for $i in (1, 2) return ("a", continue loop)
Suppose the initial value of $x
is 0
.
What is the final value of $x
after each of the
following examples?
for $i in (1, 2) return set $x := ($i, break loop)
for $i in (1, 2) return (set $x := $i, break loop)
for $i in (1, 2) return {set $x := $i; break loop;}
What is the value of the following expression?
for $i in (1, 2, 3, 4) return ($i, if ($i < 3) then continue loop else break loop)
Suppose the initial value of $list
is
()
. What is the final value of $list
after each of the following examples?
for $i in (1, 2, 3, 4) return { $list := ($list, $i); if ($i < 3) then continue loop else break loop; }
set $list := for $i in (1, 2, 3, 4) return ($i, if ($i < 3) then continue loop else break loop)
At present, the working group has defined break and continue expressions to affect while-loops only. The semantics of while are more straightforward than those of FLWOR because the body of a while-expression is a block, which does not return a value; therefore the issue of how to handle "partial iterations" does not arise.
Explicit declaration of simple functions:
Some functions that contain sequential expressions nevertheless have no externally visible side effects. For example, if the Fibonacci block in 2.3.4 While Expression were the body of a function, the function would have no externally visible side effects. Should it be possible for a user to declare such a function to be simple? Then it could be used (for example) in the for-clause of a FLWOR to iterate over Fibonacci numbers.
The following issues have been discussed:
We would need to trust the user's declaration, and an incorrect declaration might lead to unpredictable results.
There are grammar problems because the body of a simple function is an enclosed expression, while the body of a sequential function is a block. These are not syntactically distinguishable with finite look-ahead, but they are not identical because an enclosed expression does not end with a semicolon. The following approaches to deal with this grammar problem have been considered:
If a function is declared with no category, it takes an enclosed expression as its body and it is implicitly a simple function. If a function is explicitly declared "simple", it takes a block as its body (then its result is defined by an "exit" expression.)
A simple function that contains a sequential expression must have double {{curly braces}} around its body: the outer { } denote an enclosed expression and the inner { } denote a block.
Invent a new declaration like "programmed simple" to denote a simple function whose body is a block.
Change the definition of a block so that, if its final expression has no semicolon, the value of that expression is returned as the value of the block. Then let the body of a simple function be a block instead of an enclosed expression. This approach leads to some new questions: What happens if the body of a while-loop returns a value? Should semicolons be allowed outside blocks? Do we still need an "exit" expression? Etc.
Role of semicolon:
The current specification uses semicolons only inside blocks, to terminate each expression in the block. This corresponds to the use of semicolons in traditional programming languages such as Java. Alternatively, we could define a semicolon as a binary operator that evaluates its left operand expression, applies any resulting PUL, and then evaluates its right operand expression. The resulting "semicolon expression" could appear either inside or outside a block. In this approach, a semicolon might be thought of as an "apply updates" operator. This nontraditional use of a familiar operator might be confusing, and would not increase the expressive power of the language.
Mixing XDM with PUL:
In the current specification, no expression may return both a non-empty XDM instance and a non-empty pending update list. Should this restriction be removed? If so, we would no longer need the category "vacuous expression." The contexts currently requiring an updating or vacuous expression would be changed to require an updating or simple expression. In general, the category rules would be relaxed to permit mixing of updating and simple expressions.
Passing nodes to functions:
We need to specify the semantics of passing nodes to functions.
Presumably the function can modify the value of a node that is
passed to it, and this side effect is seen by the caller. But
presumably a function cannot modify the binding of a variable in
the calling environment. For example, if the caller invokes a
sequential function f($x)
, then $x
is
still bound to the same nodeid after the function call, even if the
function has deleted the node or modified its content.