5 New Kinds of Expressions

[41]    ExprSingle    ::=    FLWORExpr
| QuantifiedExpr
| SwitchExpr
| TypeswitchExpr
| IfExpr
| TryCatchExpr
| InsertExpr
| DeleteExpr
| RenameExpr
| ReplaceExpr
| UpdatingFunctionCall
| CopyModifyExpr
| OrExpr
[108]    SimpleMapExpr    ::=    PathExpr ("!" PathExpr)*

XQuery Update Facility 3.0 adds eight new kinds of expressions. The syntax and semantics of these expressions are described in the following sections.

5.1 Insert

[200]    InsertExpr    ::=    "insert" ("node" | "nodes") SourceExpr InsertExprTargetChoice TargetExpr
[199]    InsertExprTargetChoice    ::=    (("as" ("first" | "last"))? "into")
| "after"
| "before"
[204]    SourceExpr    ::=    ExprSingle
[205]    TargetExpr    ::=    ExprSingle

An insert expression inserts copies of zero or more nodes into a designated position with respect to a target node. The keywords node and nodes may be used interchangeably, regardless of how many nodes are actually inserted. The position of the inserted nodes is determined as follows:

Category Rules:
Semantics:
  1. SourceExpr is evaluated as though it were an enclosed expression in an element constructor (see Rule 1e in Section 3.9.1.3 Content XQ30). The result of this step is either an error or a sequence of nodes to be inserted, called the insertion sequence. If the insertion sequence contains a document node, the document node is replaced in the insertion sequence by its children. If the insertion sequence contains an attribute node following a node that is not an attribute node, a type error is raised [err:XUTY0004]. Let $alist be the sequence of attribute nodes in the insertion sequence. Let $clist be the remainder of the insertion sequence, in its original order.

    Note:

    Either $alist or $clist or both may be empty.

  2. TargetExpr is evaluated and checked as follows:

    1. If the result is an empty sequence, [err:XUDY0027] is raised.

    2. If any form of into is specified, the result must be a single element or document node; any other non-empty result raises a type error [err:XUTY0005].

    3. If before or after is specified, the result must be a single element, text, comment, or processing instruction node; any other non-empty result raises a type error [err:XUTY0006].

    4. If before or after is specified, the node returned by the target expression must have a non-empty parent property [err:XUDY0029].

    Let $target be the node returned by the target expression.

  3. If $alist is not empty and any form of into is specified, the following checks are performed:

    1. $target must be an element node [err:XUTY0022].

    2. No attribute node in $alist may have a QName whose implied namespace binding conflicts with a namespace binding in the "namespaces" property of $target [err:XUDY0023].

    3. Multiple attribute nodes in $alist may not have QNames whose implied namespace bindings conflict with each other [err:XUDY0024].

  4. If $alist is not empty and before or after is specified, the following checks are performed:

    1. parent($target) must be an element node [err:XUDY0030].

    2. No attribute node in $alist may have a QName whose implied namespace binding conflicts with a namespace binding in the "namespaces" property of parent($target) [err:XUDY0023].

    3. Multiple attribute nodes in $alist may not have QNames whose implied namespace bindings conflict with each other [err:XUDY0024].

  5. The result of the insert expression is an empty XDM instance and a pending update list constructed by merging the pending update lists returned by the SourceExpr and TargetExpr with the following update primitives using upd:mergeUpdates:

    1. If as first into is specified, the pending update list includes the following update primitives:

      1. If $alist is not empty, upd:insertAttributes($target, $alist)

      2. If $clist is not empty, upd:insertIntoAsFirst($target, $clist)

    2. If as last into is specified, the pending update list includes the following update primitives:

      1. If $alist is not empty, upd:insertAttributes($target, $alist)

      2. If $clist is not empty, upd:insertIntoAsLast($target, $clist)

    3. If into is specified with neither as first nor as last, the pending update list includes the following update primitives:

      1. If $alist is not empty, upd:insertAttributes($target, $alist)

      2. If $clist is not empty, upd:insertInto($target, $clist)

    4. If before is specified, let $parent be the parent node of $target. The pending update list includes the following update primitives:

      1. If $alist is not empty, upd:insertAttributes($parent, $alist)

      2. If $clist is not empty, upd:insertBefore($target, $clist)

    5. If after is specified, let $parent be the parent node of $target. The pending update list includes the following update primitives:

      1. If $alist is not empty, upd:insertAttributes($parent, $alist)

      2. If $clist is not empty, upd:insertAfter($target, $clist)

Examples:
  • Insert a year element after the publisher of the first book.

    insert node <year>2005</year>
        after fn:doc("bib.xml")/books/book[1]/publisher
  • Navigating by means of several bound variables, insert a new police report into the list of police reports for a particular accident.

    insert node $new-police-report
       as last into fn:doc("insurance.xml")/policies
          /policy[id = $pid]
          /driver[license = $license]
          /accident[date = $accdate]
          /police-reports

5.2 Delete

[201]    DeleteExpr    ::=    "delete" ("node" | "nodes") TargetExpr
[205]    TargetExpr    ::=    ExprSingle

A delete expression deletes zero or more nodes from an XDM instance. The keywords node and nodes may be used interchangeably, regardless of how many nodes are actually deleted.

Category Rules:
Semantics:
  1. TargetExpr is evaluated. The result must be a sequence of zero or more nodes; otherwise a type error is raised [err:XUTY0007]. Let $tlist be the list of nodes returned by the target expression.

  2. If any node in $tlist has no parent, it is removed from $tlist (and is thus ignored in the following step).

  3. A new pending update list is created. For each node $tnode in $tlist, the following update primitive is appended to the pending update list: upd:delete($tnode). The resulting pending update list is merged with the pending update list returned by the TargetExpr using upd:mergeUpdates, and together with an empty XDM instance forms the result of the delete expression.

Examples:
  • Delete the last author of the first book in a given bibliography.

    delete node fn:doc("bib.xml")/books/book[1]/author[last()]
  • Delete all email messages that are more than 365 days old.

    delete nodes /email/message
         [fn:currentDate() - date > xs:dayTimeDuration("P365D")]

Notes:

  • Since node deletions do not become effective until the end of a snapshot, they have no effect on variable bindings or on the set of available documents or collections within the current query.

  • The semantics of a delete expression are defined in terms of their effect on an XDM instance: the deleted nodes are detached from their parents after completion of the current query. The effects of a delete expression on persistent storage are beyond the scope of this specification.

5.3 Replace

[202]    ReplaceExpr    ::=    "replace" ("value" "of")? "node" TargetExpr "with" ExprSingle
[205]    TargetExpr    ::=    ExprSingle

A replace expression has two forms, depending on whether value of is specified.

5.3.1 Replacing a Node

If value of is not specified, a replace expression replaces one node with a new sequence of zero or more nodes. The replacement nodes occupy the position in the node hierarchy that was formerly occupied by the node that was replaced. For this reason, an attribute node can be replaced only by zero or more attribute nodes, and an element, text, comment, or processing instruction node can be replaced only by zero or more element, text, comment, or processing instruction nodes.

Category Rules:
  • A replace expression without value of specified is an updating expression.

  • The TargetExpr and expression following the keyword with can be expressions of any category.

Semantics:
  1. The expression following the keyword with is evaluated as though it were an enclosed expression in an element constructor (see Rule 1e in Section 3.9.1.3 Content XQ30). Let $rlist be the node sequence that results from this evaluation. If $rlist contains a document node, the document node is replaced in $rlist by its children.

  2. TargetExpr is evaluated and checked as follows:

    1. If the result is an empty sequence, [err:XUDY0027] is raised.

    2. If the result is non-empty and does not consist of a single element, attribute, text, comment, or processing instruction node, [err:XUTY0008] is raised.

    3. If the result consists of a node whose parent property is empty, [err:XUDY0009] is raised.

    Let $target be the node returned by the target expression, and let $parent be its parent node.

  3. If $target is an element, text, comment, or processing instruction node, then $rlist must consist exclusively of zero or more element, text, comment, or processing instruction nodes [err:XUTY0010].

  4. If $target is an attribute node, then:

    1. $rlist must consist exclusively of zero or more attribute nodes [err:XUTY0011].

    2. No attribute node in $rlist may have a QName whose implied namespace binding conflicts with a namespace binding in the "namespaces" property of $parent [err:XUDY0023].

    3. Multiple attribute nodes in $rlist may not have QNames whose implied namespace bindings conflict with each other [err:XUDY0024].

  5. The result of the replace expression is an empty XDM instance and a pending update list constructed by merging the pending update lists returned by the TargetExpr and the expression following the keyword with with the following update primitives using upd:mergeUpdates: upd:replaceNode($target, $rlist)

Example:

Replace the publisher of the first book with the publisher of the second book.

replace node fn:doc("bib.xml")/books/book[1]/publisher
with fn:doc("bib.xml")/books/book[2]/publisher

5.3.2 Replacing the Value of a Node

If value of is specified, a replace expression is used to modify the value of a node while preserving its node identity.

Category Rules:
  • A replace expression with value of specified is an updating expression.

  • The TargetExpr and expression following the keyword with can be expressions of any category.

Semantics:
  1. The expression following the keyword with is evaluated as though it were the content expression of a text node constructor (see Section 3.7.3.4 of [XQuery 3.0: An XML Query Language].) The result of this step, in the absence of errors, is either a single text node or an empty sequence. Let $text be the result of this step.

  2. TargetExpr is evaluated and checked as follows:

    1. If the result is an empty sequence, [err:XUDY0027] is raised.

    2. If the result is non-empty and does not consist of a single element, attribute, text, comment, or processing instruction node, [err:XUTY0008] is raised.

    Let $target be the node returned by the target expression.

  3. If $target is an element node, the result of the replace expression is an empty XDM instance and a pending update list constructed by merging the pending update lists returned by the TargetExpr and the expression following the keyword with with the following update primitives using upd:mergeUpdates: upd:replaceElementContent($target, $text)

  4. If $target is an attribute, text, comment, or processing instruction node, let $string be the string value of the text node constructed in Step 1. If Step 1 did not construct a text node, let $string be a zero-length string. Then:

    1. If $target is a comment node, and $string contains two adjacent hyphens or ends with a hyphen, a dynamic error is raised [err:XQDY0072].

    2. If $target is a processing instruction node, and $string contains the substring "?>", a dynamic error is raised [err:XQDY0026].

    3. In the absence of errors, the result of a replace expression is an empty XDM instance and a pending update list constructed by merging the pending update lists returned by the TargetExpr and the expression following the keyword with with the following update primitives using upd:mergeUpdates: upd:replaceValue($target, $string).

Examples:

Increase the price of the first book by ten percent.

replace value of node fn:doc("bib.xml")/books/book[1]/price
with fn:doc("bib.xml")/books/book[1]/price * 1.1

5.4 Rename

[203]    RenameExpr    ::=    "rename" "node" TargetExpr "as" NewNameExpr
[205]    TargetExpr    ::=    ExprSingle
[206]    NewNameExpr    ::=    ExprSingle

A rename expression replaces the name property of a data model node with a new QName.

Category Rules:
Semantics:
  1. TargetExpr is evaluated and checked as follows:

    1. If the result is an empty sequence, [err:XUDY0027] is raised.

    2. If the result is non-empty and does not consist of a single element, attribute, or processing instruction node, [err:XUTY0012] is raised.

    Let $target be the node returned by the target expression.

  2. NewNameExpr is processed as follows:

    1. If $target is an element node, let $QName be the result of evaluating NewNameExpr as though it were the name expression of a computed element constructor (see Section 3.9.3.1 Computed Element Constructors XQ30). If the namespace binding of $QName conflicts with any namespace binding in the namespaces property of $target, a dynamic error is raised [err:XUDY0023].

    2. If $target is an attribute node, let $QName be the result of evaluating NewNameExpr as though it were the name expression of a computed attribute constructor (see Section 3.9.3.2 Computed Attribute Constructors XQ30). If $QName has a non-absent namespace URI, and if the namespace binding of $QName conflicts with any namespace binding in the namespaces property of the parent (if any) of $target, a dynamic error is raised [err:XUDY0023].

    3. If $target is a processing instruction node, let $NCName be the result of evaluating NewNameExpr as though it were the name expression of a computed processing instruction constructor (see Section 3.9.3.5 Computed Processing Instruction Constructors XQ30), and let $QName be defined as fn:QName((), $NCName).

  3. The result of the rename expression is an empty XDM instance and a pending update list constructed by merging the pending update lists returned by the NewNameExpr and TargetExpr with the following update primitives using upd:mergeUpdates: upd:rename($target, $QName).

Examples:
  • Rename the first author element of the first book to principal-author.

    rename node fn:doc("bib.xml")/books/book[1]/author[1]
    as "principal-author"
  • Rename the first author element of the first book to the QName that is the value of the variable $newname.

    rename node fn:doc("bib.xml")/books/book[1]/author[1]
    as $newname

Note:

The effects of a rename expression are limited to its target node. Attributes and descendants of the target node are not affected. If a global change of names or namespaces is intended, some form of explicit iteration must be used. The following example illustrates such a global change. The example operates on the node bound to variable $root and all its attributes and descendants, changing all QNames with the prefix abc to have a new prefix xyz and a new namespace URI http://xyz/ns.

for $node in $root//abc:*
let $localName := fn:local-name($node),
    $newQName := fn:concat("xyz:", $localName)
return (
   rename node $node as fn:QName("http://xyz/ns", $newQName),
   for $attr in $node/@abc:*
   let $attrLocalName := fn:local-name($attr),
       $attrNewQName := fn:concat("xyz:", $attrLocalName)
   return
      rename node $attr as fn:QName("http://xyz/ns", $attrNewQName)
)

5.5 Dynamic Updating Function Invocation

[207]    UpdatingFunctionCall    ::=    "invoke" "updating" PrimaryExpr "(" (ExprSingle ("," ExprSingle)*)? ")"

A dynamic updating function call dynamically invokes an updating function. A dynamic updating function call is constrained by the grammar so that it cannot be a partial function applicationXQ30.

Category Rules:
Semantics:

A dynamic updating function call is evaluated like a dynamic function invocation, as specified in Section 3.2.2 Dynamic Function Call XQ30. However unlike [7.11 Dynamic Function Invocation] it can invoke either an updating function or a simple function, and could therefore potentially return a non-empty pending update list.

The result of the dynamic updating function call is the XDM instance returned by the function invoked, as well as a pending update list constructed by merging the pending update lists returned by the PrimaryExpr and any argument expressionsXQ30, with the pending update list returned by the function invoked using upd:mergeUpdates.

Example:
  • Dynamically call the fn:put() function.

    let $f := fn:put#2
    return invoke updating $f(<newnode/>,"newnode.xml")

5.6 Copy Modify

[208]    CopyModifyExpr    ::=    "copy" "$" VarName ":=" ExprSingle ("," "$" VarName ":=" ExprSingle)* "modify" ExprSingle "return" ExprSingle

A copy modify expression can be used to create modified copies of existing nodes in an XDM instance. Each node created by a copy modify expression has a new node identity. The result of a copy modify expression is an XDM instance that may include both nodes that were created by the copy modify expression and other, previously existing nodes.

A copy modify expression consists of three clauses, denoted by the keywords copy, modify, and return.

Category Rules:
  • If all of the copy modify expression's copy and return clauses have operand expressions that are simple expressions, then the copy modify expression is a simple expression.

  • If any of the copy modify expression's copy or return clauses have operand expressions that are updating expressions, then the copy modify expression is a updating expression.

  • The operand expressions of any of the clauses of a copy modify expression can be expressions of any category.

Semantics:
  1. The copy clause contains one or more variable bindings, each of which consists of a variable name and an expression called the source expression. Each variable binding is processed as follows:

    1. The result of evaluating the source expression must be a single node [err:XUTY0013]. Let $node be this single node.

    2. A new copy is made of $node and all nodes that have $node as an ancestor, collectively referred to as copied nodes. Each copied node receives a new node identity. The parent, children, and attributes properties of the copied nodes are set so as to preserve their inter-node relationships. The parent property of the copy of $node is set to empty. Other properties of the copied nodes are determined as follows:

      1. For a copied document node, the document-uri property is set to empty.

      2. For a copied element node, the type-name property is set to xs:untyped, and the nilled, is-id, and is-idrefs properties are set to false.

      3. For a copied attribute node, the type-name property is set to xs:untypedAtomic and the is-idrefs property is set to false. The is-id property is set to true if the qualified name of the attribute node is xml:id; otherwise it is set to false.

      4. The string-value of each copied element and attribute node remains unchanged, and its typed value becomes equal to its string value as an instance of xs:untypedAtomic.

        Note:

        Implementations that store only the typed value of a node are required at this point to convert the typed value to a string form.

      5. If copy-namespaces mode in the static context specifies preserve, all in-scope-namespaces of the original element are retained in the new copy. If copy-namespaces mode specifies no-preserve, the new copy retains only those in-scope namespaces of the original element that are used in the names of the element and its attributes.

      6. All other properties of the copied nodes are preserved.

    3. The variable name is bound to the top-level copied node generated in the previous step. The scope of this variable binding includes all subexpressions of the containing copy modify expression that appear after the variable binding clause, including the source expressions of later variable bindings, but it does not include the source expression to which the current variable name is bound.

  2. The expression in the modify clause is evaluated, resulting in a pending update list (denoted $pul) and an XDM instance. The XDM instance is discarded, and does not form part of the result of the copy modify expression.

    If the target node of any update primitive in $pul is a node that was not newly created in Step 1, a dynamic error is raised [err:XUDY0014]. If $pul contains a upd:put update primitive, a dynamic error is raised [err:XUDY0037].

  3. Let $revalidation-mode be the value of the revalidation mode in the static context of the library or main module containing the copy modify expression, and $inherit-namespaces be the value of inherit-namespaces in the static context of the copy modify expression. The following update operation is invoked: upd:applyUpdates($pul, $revalidation-mode, $inherit-namespaces). The effect of this operation is to make the updates specified in the modify clause effective on the copied nodes.

    Note:

    In the event of incompatible updates, the upd:applyUpdates operation may raise an error, as described in [8.2.3 upd:applyUpdates].

  4. The return clause is evaluated, resulting in a pending update list and an XDM instance. The result of the copy modify expression is the XDM instance returned, as well as a pending update list constructed by merging the pending update lists returned by any of the copy modify expression's copy or return clause operand expressions using upd:mergeUpdates. During evaluation of the return clause, changes applied to copied nodes by the preceding step are visible.

Examples:
  • Return a sequence consisting of all employee elements that have Java as a skill, excluding their salary child-elements:

    for $e in //employee[skill = "Java"]
    return 
       copy $je := $e
       modify delete node $je/salary
       return $je
  • The following example copies a node, modifies the copy, and returns both the original node and the modified copy:

    let $oldx := /a/b/x
    return
       copy $newx := $oldx
       modify (rename node $newx as "newx", 
               replace value of node $newx with $newx * 2)
       return ($oldx, $newx)
    

    Note:

    No persistent changes to the underlying data result from this example.

5.7 Transform With

[97]    TransformWithExpr    ::=    UnaryExpr ( "transform" "with" "{" Expr? "}" )?

The TransformWithExpr is a convenient short hand for the common use case of wanting to apply updates to a copy of a single node. If N and U are arbitrary expressions, and $v is a variable name that is otherwise unused in U, then the following TransformWithExpr:

N transform with { U }

is equivalent to the following longer form CopyModifyExpr:

copy $v := N
modify $v!(U)
return $v

5.8 Compatibility of Updating Expressions

The rules defining compatibility of updating expressions within a snapshot are defined in [8.2.3 upd:applyUpdates].

Note:

The effect of these rules is as follows:

  1. If any node is affected by more than one rename expression within a snapshot, a dynamic error is raised [err:XUDY0015].

  2. If any node is affected by more than one replace expression (without value of being specified) within a snapshot, a dynamic error is raised [err:XUDY0016].

  3. If any node is affected by more than one replace value of expression within a snapshot, a dynamic error is raised [err:XUDY0017].

  4. If multiple calls to fn:put operate on the same URI in the same snapshot, a dynamic error is raised [err:XUDY0031].

  5. Within a given snapshot, if an element node E is the target of a replace value of expression, and the children of E are also modified by other expressions, the final children of E are determined by the replace value of expression. For example:

    • Suppose that $A is bound to an element node that has a child element named B. Suppose that the following expressions are evaluated in the same snapshot:

      replace node $A/B with <C>Hello</C>,
      replace value of node $A with <D>Goodbye</D>

      The expressions on the left and right side of the comma can be evaluated in any order. No error is raised. At the end of the snapshot, the children of $A will consist of a single text node with the content "Goodbye".