XML Prague 2026
Juri Leino — Jinntec GmbH
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
<root> <child>a</child> <child /> </root>
document - element(root) - element(child) - text(a) - element(child)
$document//child
( <child>a</child>, <child /> )
parent a reference to the parent JNode in the tree
value the value of the array member or map entry
key the map key or array index
position needed to handle "mixed" content
jtree()
jnode-value()
jnode-key()
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-value()
<node id="something">
content
</node>
{
'key': [1,2,3]
} { "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 }? $propertyEXPR => my:f() => my:g()
my:g(my:f(EXPR))
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}`]``
}()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)
fn:filter( $input as item()*, $predicate as fn(item(), xs:integer) as xs:boolean? ) as item()*
declare function my:fn ($a, $b) { $a, $b };
declare function my:fn ($a) { my:fn($a, ()) };
declare function my:fn ($a, $b) { $a, $b };
declare function my:fn ($a) { my:fn($a, ()) };
my:fn(12)
declare function local:many-parameters (
$a := 1, $b := 1, $c := 1, $d :=1
) {
$a + $b * $c * $d
};
local:many-parameters()declare function local:many-parameters (
$a := 1, $b := 1, $c := 1, $d :=1
) {
$a + $b * $c * $d
};
local:many-parameters(c:=2, a:=0)doc($uri, $options)
parse-csv("a|b|c", {
"field-delimiter": "|"
})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}`) }
<xsl:stylesheet
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
xmlns:err="http://www.w3.org/2005/xqt-errors"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="#all"
version="4.0"
>
...
<xsl:choose> <xsl:when test="$n ge 0"> <xsl:sequence select="1"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="-1"/> </xsl:otherwise> </xsl:choose>
<xsl:if test="$n ge 0" then="1" else="-1" /><xsl:variable name="n" select="a"/> <xsl:choose> <xsl:when test="$n = (1, 2, 3, 4)"> <xsl:sequence select="../small"/> </xsl:when> <xsl:when test="$n = (5 to 20)"> <xsl:sequence select="../medium"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="../large"/> </xsl:otherwise> </xsl:choose>
Text
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" fixed-namespaces="#default" exclude-result-prefixes="#all" version="4.0"> ...
<xsl:choose> <xsl:when test="$n lt $low"> <xsl:sequence select="../below"/> </xsl:when> <xsl:when test="$n gt $high"> <xsl:sequence select="../above"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="../within"/> </xsl:otherwise> </xsl:choose>
<xsl:choose> <xsl:when test="$n lt $low" select="../below"/> <xsl:when test="$n gt $high" select="../above"/> <xsl:otherwise select="../within"/> </xsl:choose>
<xsl:function
name="f:book-to-json"
as="map(*)">
<xsl:param name="book" as="element(book)">
<xsl:sequence select="{
'title' : string($book/title),
'author' : array { $book/author ! string() },
'date' :
let $d := $book/publication
return
if (current-date() lt xs:date($d))
then $d
else 'Don't release'
}"/>
</xsl:function><xsl:function
name="f:book-to-json"
as="map(*)">
<xsl:param name="book" as="element(book)">
<xsl:sequence select="{ 'title' : string($book/title), 'author' : array { $book/author ! string() }, 'date' : let $d := $book/publication return if (current-date() lt xs:date($d)) then $d else 'Don't release' }"/>
</xsl:function><xsl:function name="f:book-to-json" as="map(*)"> <xsl:param name="book" as="element(book)"> <xsl:select> { 'title' : string($book/title), 'author' : array { $book/author ! string() }, 'date' : let $d := $book/publication return if (current-date() lt xs:date($d)) then $d else 'Don't release' } </xsl:select> </xsl:function>
<xsl:for-each-group
select="1 to 4, 5, 7 to 9, 10 to 12, 14, 15, 20 to 22"
split-when="$next ne ($group[last()] + 1)">
<group>{ current-group() }</group>
</xsl:for-each-group><xsl:for-each-group
select="1 to 4, 5, 7 to 9, 10 to 12, 14, 15, 20 to 22"
split-when="$next ne ($group[last()] + 1)">
<group>{ current-group() }</group>
</xsl:for-each-group><xsl:for-each-group
select="1 to 4, 5, 7 to 9, 10 to 12, 14, 15, 20 to 22"
split-when="$next ne ($group[last()] + 1)">
<group>{ current-group() }</group>
</xsl:for-each-group><group>1 2 3 4 5</group> <group>7 8 9 10 11 12</group> <group>14 15</group> <group>20 21 22</group>
<xsl:function name="f:inRange"> <xsl:param name="n" as="element()"/> <xsl:param name="low" required="no" select="0"/> <xsl:param name="high" required="no"> <xsl:call-template name="findNumberLimit"/> </xsl:param> <!-- the actual function --> </xsl:function>