What's in it for me?
Declarative Amsterdam 2025
Juri Leino and John Lumley
〰 BREAK 〰
〰 BREAK 〰
start
finish
qt4cg.org — A Community Group under W3C
start
finish
qt4cg.org — A Community Group under W3C
qt4cg.org — A Community Group under W3C
start
finish
Sections with significant changes in the TOC
New functions
Previous/ Next
Links to Issue and PR
parent: a reference to the parent JNode in the tree.
content: the value of the array member or map entry.
selector: the map key or array index that distinguishes this child from its siblings.
position: needed to handle "mixed" content
jtree()
jnode-content()
jnode-selector()
jnode-position()
[ "a", "b", "c"]
/*[1]
/..
/*[last()]
/string()jtree([ "a", "b", "c"])
/*[1]
/..
/*[last()]
/string(){ "fr": { "capital": "Paris", "languages": [ "French" ] }, "de": { "capital": "Berlin", "languages": [ "German" ] } } //languages
{ "fr": { "capital": "Paris", "languages": [ "French" ] }, "de": { "capital": "Berlin", "languages": [ "German" ] } } //child::get("languages")
{ "fr": { "capital": "Paris", "languages": [ "French" ] }, "de": { "capital": "Berlin", "languages": [ "German" ] } } //languages/jnode-content()
<node id="something">
content
</node>
{
'key': [1,2,3]
}〰 BREAK 〰
CODE
CONTEXT
RESULT
SELECT EXAMPLE
RUN
SELECT CONTEXT
TYPE
{ "this": "is", "a": "map" }map
{ "this": "is", "a": "map" }{ "test 1": 10 }?("test 1"){ 1: 10 }?1
{ "test": 10 }?test{ "test 1": 10 }?("test 1"){ "test 1": 10 }? "test 1"{ "test 1": 10 }?($property){ "test 1": 10 }? $propertyrecap
EXPR => my:f() => my:g()
my:g(my:f(EXPR))
recap
1 to 3 => sum() => math:pow(2) => function ($i) { ``[The square of the sum is `{$i}`]`` }()
1 to 3 => for-each(math:pow(?,2)) => sum() => function ($i) { ``[The sum of squares is `{$i}`]`` }()
recap
1 to 3
=!> math:pow(2)
=> sum()
=> function ($i) {
``[The sum of squares is `{$i}`]``
}()1 to 3 ! math:pow(2,.)
1 to 3
=!> fn($a){math:pow(2, $a)}()
function argument order
1 to 3 ! (. + 2)
1 to 3
=!> fn($a){ $a + 2 }()
RHS has to be a function call
3 -> math:pow(2, .)
EXPR -> EXPR
{ "number": 1, "name": "template" }
-> `This is {?number} string {?name}`not a string constructor
let $g := fn() {}
let $f := function () {}return ($f(), $g())
let $id := fn{ . }
$id(1)
no arguments but the context value
if (COND) { "COND was true" }
braced-if (without else)
EXPR otherwise "fallback value"otherwise
fn ($e as element()) {
(: do something with the element :)
}element wildcards
fn ($e as element(*)) {
(: do something with the element :)
}element wildcards
fn ($e as element(*:div)) {
(: work with all the divs :)
}element wildcards
declare default namespace ##any; fn ($e as element(div)) { (: work with all the divs :) }
element wildcards
//element(div|section)
(: select divs and sections :)
UnionNodeTests
fn ($input as (map(*)|array(*))) {
$input?1
}
ChoiceItemTypes
let ($head, $tail) := (1 to 3) return ($tail, $head)
Destructuring a sequence
let ($p, $q) := (1 to 3) return ($p, $q)
Destructuring a sequence
let $m := { "yksi": 1, "kaksi": 2 }
let ${$yksi} := $m
return $yksi
Destructuring a map
let $[$uno, $dos] := [ 23, 42 ] return $uno * $dos
Destructuring an array
$my:pool =?> area()
record =?> function(record, *)
$my:pool?area($my:pool)
〰 BREAK 〰
declare context value as document() external := document { (: the default :) }
declared namespaces: xs, fn, err
declare namespace array="???"; array:filter([1,-3,4,0], fn { math:abs(.) > 1 })
array:filter([1,-3,4,0], fn { math:abs(.) > 1 })
declared namespaces: xs, fn, err, map, array, math
declare option output:method "json";
array:filter([1,-3,4,0], fn {
math:abs(.) > 1
})declared namespaces: xs, fn, err, map, array, math, output
switch ($n) {
case "one" return xs:double(1)
case "two" return xs:double(2)
default return xs:double('NaN')
}
switch with curly braces
switch ($n) {
case "one", "un" return xs:double(1)
case "two" return xs:double(2)
default return xs:double("NaN")
}
multiple cases
declare type my:binary as (xs:base64binary | xs:hexBinary);
enum
declare type my:color as enum(
"red", "green", "blue"
)record
declare type my:rectangle as record(
height as xs:decimal,
width as xs:decimal
)record
declare record my:rectangle (
height as xs:decimal,
width as xs:decimal
)extendable record
declare record my:rectangle (
height as xs:decimal,
width as xs:decimal,
*
)record with a method
declare record my:rectangle (
height as xs:decimal,
width as xs:decimal,
area as fn(my:rectangle) as xs:decimal := fn ($self) {
$self?height × $self?width
}
)record with a method that is a focus function
declare record my:rectangle (
height as xs:decimal,
width as xs:decimal,
area as fn(my:rectangle) as xs:decimal := fn {
?height × ?width
}
)try-catch with error map
try {
error(QName("local:error"),
"I can't let you do that, Dave.",
{ "custom": true() })
} catch * {
trace($err:map)
}{
'code': 'local:error',
'description': 'I can't let you do that, Dave.',
'value': { "custom": true() },
'lineNumber': 2,
'columnNumber': 4,
'module': 'my-module.xq',
'stacktrace': …,
⋮
}try-catch with finally
try {
let $i := 0 return 1 div $i
} catch * {
$err:description
} finally {
message(`1 div {$i}`) }
〰 QUESTIONS 〰