How to cite this paper
Kay, Michael. “The XSLT/XPath/XQuery 4.0 Standards: a High-Level Perspective.” Presented at Balisage: The Markup Conference 2026, Washington, DC, August 3 - 7, 2026. In Proceedings of Balisage: The Markup Conference 2026. Balisage Series on Markup Technologies, vol. 31 (2026). https://doi.org/10.4242/BalisageVol31.Kay01.
Balisage: The Markup Conference 2026
August 3 - 7, 2026
Balisage Paper: The XSLT/XPath/XQuery 4.0 Standards: a High-Level Perspective
Michael Kay
Founder and Director of Innovation
Saxonica
Michael Kay is the founder and Director of Innovation at Saxonica.
He was the original developer of the Saxon XSLT and XQuery processor,
and was the editor of the XSLT 2.0 and 3.0 specifications. He
was instrumental in establishing a W3C community group to create
4.0 versions of the XSLT, XQuery, and XPath languages. Since 2004 Saxonica
has been a leading participant in both the development of the language
specifications and in delivering high quality implementations of the standards.
Michael is based in Reading, UK.
Abstract
A W3C Community Group is in the process of developing proposals
for 4.0 versions of XSLT, XPath, and XQuery (collectively, QT4).
This paper describes the original
objectives of this project and the extent to which they have been achieved.
It does this within the framework of some general observations about standards
and the factors that make standards successful and unsuccessful.
Table of Contents
- About this Paper
- The current state of the QT4 standards
-
- Completed work
- Work in Progress
- Outstanding requirements
- Standardization in the XML community
- Lessons from history
- The standardization process
About this Paper
The sheer number of new features added to the 4.0 specifications makes it very
difficult to provide a concise summary of what's new. Even in the release
notes
for Saxon 13, which implements many of the new features, we resorted to
the headline summary "More than 175 features from the draft 4.0 specifications
are now available...." There are various ways of tracking the detailed changes:
the specification itself contains a "changes" summary below the section heading
of any section that contains substantive changes, and these link to the GitHub
Pull Requests that contain the detailed text of each change. Test cases in the
extensive test suite (also available on GitHub) are also linked to pull requests,
and pull requests that have been implemented in a released Saxon version include
a GitHub label "In Saxon 12" or "In Saxon 13".
As a taster, I published a list of 101 Fun things to
do with QT4: none of them
described in any detail, but a list intended for easy reading where, if particular
features
whet your appetite, you can go to the specs and investigate further.
So I won't make any attempt in this paper to provide a comprehensive list
of new features. Instead, I will take a step back, and try to discern
some overall themes.
What is the status of the work? It's six years since I first proposed
the QT4 initiative [Kay 2020], and four years since the QT4 community group started
work to flesh out a definition of the 4.0 versions of XSLT, XPath, and XQuery.
The work is ongoing and subject to revision and change as the work proceeds.
At a process level, there is still some work to do to decide under what auspices
the work should be published. W3C no longer has a formal XML Activity, and there are
no official working groups chartered to take the XML standards forward. QT4 is not
alone in making technical progress through the informal mechanism of W3C Community
Groups,
but these do not have the authority to publish official Recommendations.
As the work nears completion, we can expect to see the politics get resolved,
but meanwhile the work is presented to the world to accept or reject based
on its technical merits.
Process is important, but the significant parts of the process to date have
been those that facilitated the technical collaboration to produce a high quality
specification, rather than the process for getting an official stamp of approval
on the final publication (including a formal consultation process). Because process
is important, I'll share my thoughts on the subject.
The current state of the QT4 standards
We can divide this into three parts.
-
What new features are there in the spec that appear to be stable and complete and
require no further work?
-
What features in the spec are known to be incomplete and should be considered work
in progress?
-
What requirements remain to be addressed?
I'll consider these three questions in the following subsections of the paper.
Completed work
It's never over till the fat lady sings, as they say, so we can never say definitively
that a feature already added to the spec
is finished and stable and won't change before final publication. But there are some
things we can be 95% confident about. Or at any
rate, we can be confident that any further changes in these areas will be fairly superficial.
In this category I would include the following:
-
Most of the 92 new functions added to the core function library, and the 154 extensions to
the behavior of existing functions.
Many of the new functions are very simple, but hopefully also very practical.
Some are pure convenience
functions, like fn:characters which splits a string into single characters, or fn:is-NaN
which tests whether a value is the special floating-point value NaN, or fn:foot
which returns the last item in a sequence.
Many of the new functions are higher-order, producing effects
that would otherwise have required custom syntax: some of my favorites are fn:highest and fn:lowest
which return the items in a sequence that have the highest or lowest values for some
computed property; fn:take-while
which returns all the items in a sequence up until the first that satisfies some condition;
and
fn:all-equal and fn:all-different which test respectively whether all items in a sequence
are equal, or whether they are all distinct. Also fn:transitive-closure which does what the name suggests.
Other new functions incorporate powerful new capabilities to process external data
formats. In this category we have fn:parse-html
and fn:parse-csv to process HTML5 and CSV input data respectively, and fn:invisible-xml to process
arbitrary input conforming to a user-supplied grammar. Another big one is fn:element-to-map which does
XML-to-JSON conversion according to the design outlined in [Kay 2023].
More modestly, fn:parse-uri splits a URI into its parts,
and fn:build-uri puts them back together again.
Many existing functions have acquired new options. fn:deep-equal, for example, has options to control
exactly how comparisons are performed, such as whether whitespace and namespace prefixes
are to be considered significant. The fn:doc and fn:document function have options to enable
DTD and XSD validation and XInclude processing. The fn:round function has options to control rounding mode.
-
One of the benefits of higher-order functions is that many powerful capabilities can
be added to the language
without new syntax. But I think some of the XPath syntax
extensions will also prove popular. How did we
ever manage without the otherwise
operator? - the expression @discount otherwise 0
return the value of @discount if the attribute exists, or zero otherwise. Extensions to for
expressions in XPath (or the for clause of FLWOR expressions in XQuery) to process maps and arrays
will probably find ready acceptance. And I think the abbreviated syntax for simple
inline functions will also
have a big impact: writing a callback as fn{@name} rather than function($e as element(*)) { $e/@name }
doesn't just save keystrokes, it makes a substantive difference to the aesthetics
and therefore the usability of higher order functions.
-
On the XSLT front, there are also a few simple features that look finished and stable. The xsl:if instruction
now has then and else attributes, while xsl:when and xsl:otherwise
have a select attribute, and there is a new xsl:switch instruction for a multiway conditional.
The ability to write all the template rules for a mode as children of the xsl:mode element provides
a way to make code more readable and therefore easier to debug.
-
Generally we have tried to do as much as possible without significant changes to the
data
model or type system,
because such changes are always more disruptive. But a few changes in that area stand
out as being particularly
successful:
-
Choice types, for example, (xs:date | xs:time | xs:dateTime), or
(element(E) | document(element(E))).
-
Enumeration types, for example, enum("red", "green", "blue").
-
Changes to the function conversion rules, now renamed coercion rules, which allow
downcasting:
you can specify the required type of a function parameter as, say xs:positiveInteger, and the
caller can supply the value 42 without explicitly casting it to that type: the cast will
happen automatically. This makes the use of derived types such as xs:positiveInteger much
more attractive.
-
Maps now retain order. The immediate benefit is that when you perform a transformation
on JSON input, and serialize the result, the output is now readable rather than being
garbled.
Work in Progress
There are a number of areas in the specifications where a great deal of progress has
been made, but a number
of issues remain open. These tend to be related and intertwined, so progress in one
area can involve changes
in another.
At Balisage 2025 I reported on the introduction of JNodes [Kay 2025], and most of the ideas presented in that paper
found their way into the draft specification, and have proved robust. But:
-
There are some loose ends regarding the handling of arrays whose members are XDM sequences
rather than
single items; and similarly, maps whose entries are general XDM sequences. These constructs
never arise from parsing JSON,
but they can arise in the general case of a constructed tree, and we need to work
out the detail of what to do with them.
-
The proposed syntax $a/get("date of birth") (also available with other axes, for example,
as $a/descendant::get("date of birth")) met with some resistance. The current proposal, which
still needs a little work to finalize, is to substitute the syntax $a/"date of birth" or
$a/descendant::{"date of birth"). In both cases, in principle, the string literal
"date of birth" can be replaced with an expression, but this potentially leads to
conflicts with the semantics of expressions such as $a/name() or $a/jvalue().
-
While the use of JNodes in path expressions for selection within JSON-derived trees
is now quite well
defined, there are still open questions
about transformation of such trees using the XSLT recursive-descent
processing model with template rules. What should the syntax be for match patterns
that match JNodes? What should
their default priority be? What should the built-in template rules do when there is
no explicit match? These
areas are all still being explored.
Record types were introduced in the very first proposal for 4.0: the idea is that
the type record(partNr as xs:string, price as xs:decimal)
should be descriptive of a map containing two entries, an entry with key "partNr" whose value is a string, and an entry with key "price"
whose value is a decimal number. This correlates well with a common way that maps
are used, and many of the new functions and operators have found
record types convenient to use in defining their argument types and result types.
But as with JNodes, record types have been subject to some changes
as the spec has progressed, and we're probably not done yet. Some of the areas of
change have been:
-
We have abandoned the flag that defined a record type as being extensible (allowing
it to contain fields other than those listed). This
went against the aim of strict typing for record types, allowing an expression such
as $product?part-nr (with a misspelled
field name) to be flagged as a static error.
-
We've also dropped the ability to define some of the fields as being optional. We
found there was too much scope for confusion in that
absent data could be represented either by a field that was absent, or by a field
that was present but empty. In the current design, absent
data in a record is always indicated by a field whose value is an empty sequence.
-
As originally defined, a record type was simply a predicate applied to a map. We have
now introduced the idea that a map should have
a type annotation identifying it explicitly as an instance of a specific map type.
But I don't think we have yet worked through all the
implications of this change, for example, the precise rules as to whether two record
types are "the same type".
-
As a replacement for the ability to define record types as extensible, there's a suggestion
that we might define one record
type to be an extension of another.
-
We have syntax in both XQuery and XSLT to declare named record types. One of the advantages
of making them named is that record types
can become recursive: for example, a LISP enthusiast might define the record type
my:list as
record(car as item()*, cdr as my:list?): a two-entry map containing an arbitrary data value called cdr, and
an optional [pointer to a] my:list called cdr. I don't think we've yet tested the implementability and usability
of recursive record types in anger, and there might be changes once we do.
-
We've defined that named record types should have an associated constructor function
to create instances of the named record type.
But we've also found use cases where no constructor function is wanted (in particular,
where the record type is designed explicitly to
be the result type of a function such as fn:parse-uri) and we've also found cases where a customized constructor function
(or set of constructor functions) is preferred over one that is system-generated.
Records have proved their worth and will no doubt feature in the final spec, but there
are still rough edges to be smoothed out.
Outstanding requirements
As well as features that appear to be done and dusted, and other features that are
done but still need some dusting, we have
a wish-list of bright ideas that someone would like included in the spec. In some cases there is consensus that
these features
would be nice to have; in other cases their value is disputed. What characterizes
them all, however, is that the spec could be published
without them: they are not essential to declaring victory.
Some of these ideas come from within the Community Group, some come from outside.
Some of them are well formulated proposals, others
are sketchy ideas. The problem is, they are opened faster than we can close them.
Every working group hits the problem that at some stage it wants to declare itself
finished, but it still has this pool of good ideas
for making the spec better. Essentially there's a social process within the working
group when the consensus starts to form that we're in the
end game and must politely decline to do any further work. Of course, there's still
a tendency to accept ideas if someone steps up and does
all the detailed work to define the precise syntax and semantics and to write test
cases. But even then, working groups eventually lose
patience and declare that the proposal is out of time.
But until then, there are still some intriguing ideas on the table. There's a big
proposal on
generators: functions whose repeated
application produces an infinite sequence. Dimitre Novatchev is planning to present
that proposal at this conference.
Other proposals are more limited in scope: a proposal to allow comment lines in CSV
files, for example, or to
add named capture groups in regular expressions, or to add a function that converts
maps to element nodes, or to do "deep update"
of a tree derived from JSON processing. The Community Group will only be able to declare
itself finished when it has made
a decision (one way or the other) on all these good ideas.
Standardization in the XML community
The XML community's attitude to standards is driven by the nature
of XML itself. As a standard for transmission of data between heterogenous
systems, and even more so as a standard for long-term storage of information
of lasting value, XML instrinsically needs to be very rigorously standardised,
and moreover, changes to the standard over time are generally unwelcome,
as proven by the failure of the 1.1 version: the cost to the community of
adopting a change exceeds the benefit. The same observations can be made
for JSON, and it is notable that for both XML and JSON, only very small
changes have been attempted once they had become established in widespread use.
Even fixing widely-acknowledged bugs (such as the fact that JSON allows unpaired
Unicode surrogates, or the fact that XML fails to say exactly what constitutes
a valid namespace URI) has proved remarkably difficult.
This community attitude to standardisation naturally extends to closely
associated standards such as XML Schema. The need for standards in areas
such as transformation and query languages is perhaps not as strong;
there is no intrinsic reason why multiple programming languages and
APIs (and successive versions thereof), should not thrive just as happens
in the field of general-purpose programming languages. What's different
here is the architecture of the web: if stylesheets are to be executed
in the browser, then the stylesheet language needs to be supported by
every browser, and until recently, the browser environment has been a
barrier to innovation because the platform is tightly controlled by a
cabal of browser vendors. The standardisation culture for the XSLT
environment is thus conditioned partly by the original motivation of
client-side transformation, which demands rigid standards, and partly
by the area where it has seen most success, as a server-side domain-specific
transformation language, where there is more room for variety and innovation:
a culture that has enabled newer versions to thrive in a way that newer
versions of XML and JSON could not.
Lessons from history
QT 4.0 is, as the number suggests, the fourth phase of standardisation
in this area. The 1.0 standards were produced very quickly, and proved
highly successful, though they had many technical flaws. Each subsequent
phase has taken longer: seven years to version 2.0, a decade to version 3.0,
perhaps even longer (who knows) to version 4.0. On many measures the standards
have improved in quality: they are more precise, less ambiguous, better
supported by test suites, there are certainly fewer gaps in functionality,
and fewer usability quirks. But some of the new features that were introduced
have not achieved widespread adoption. Can we look at the features that were
successful, and those that weren't, and spot any trends?
My personal attitude is that the success of a standard, and of new features
in a standard, is more related to the cost of adoption than to the benefit
of adoption. The most significant innovation in XSLT 2.0 was schema awareness,
and twenty years later it seems that only a small minority of the user
community is using the feature. This is not because there is no benefit:
our experience suggests that when developing complex XSLT-based applications,
schema awareness gives many productivity benefits through easier debugging.
But there is a significant up-front adoption cost. Writing the first version of your
code takes longer,
even if you get to a complete debugged application more quickly. Similar observations
apply to some of
the big ideas in 3.0, such as streaming and packages, both of which deliver
significant benefits that only a small number of enlightened users are taking advantage
of.
By contrast, the things that have been most successful have been those that
could be adopted incrementally without any major change. In XSLT and XPath 2.0,
grouping, regular expressions, XSLT functions, date and time manipulation,
conditional expressions. In 3.0, maps, xsl:iterate, accumulators. Higher-order
functions occupy a middle ground: the cost of adoption here is primarily the
challenge of learning a new concept in computer science and software engineering,
and adoption has steadily increased as the same basic idea has become familiar in
other
languages such as Java, C#, and Javascript.
I think that the vast majority of changes in QT4 are incremental in this
sense: once users discover that the feature exists and is available in their
chosen products, they will be quick to take advantage of it.
The standardization process
Who are the stakeholders in the standards process?
I will identify four: the users, the implementors, the funders, and the standards
organizations themselves.
What we end up delivering depends on how these four groups of stakeholders play the
game, and that in turn
depends on what they are trying to achieve.
What I'm going to say here draws not just on experience with QT4, but on other experience
within W3C
and before that with other standardization projects: Codasyl, ANSI, BSI, ISO, ECMA,
in some of which
I was a direct participant and in others merely an interested observer. And this over
a timespan of
fifty years.
The mechanics of the standardization process have of course changed immeasurably over
that timeframe.
In the Codasyl days I would type a proposal on a typewriter, make 40 copies, and address
40 envelopes,
making sure they arrived three weeks before the next meeting, which was always somewhere
in the US and lasted
a week. Compare that to the process of creating a pull request on GitHub, and getting
feedback an hour later.
But although the mechanism may have
changed, the factors that make some proposals successful and others unsuccessful have
not.
On most of the groups I have worked with, users have acted primarily as reviewers
rather than
initiators. A genuine user (by which I mean someone who actually does hands-on development
and
knows the specs well) is a great asset, even if review and verification is the only
contribution they make.
Unfortunately some user organisations instead send a supernumerary,
someone who is no longer actively engaged and whose technical knowledge is rusty;
these people can be time-wasters.
The QT4 activity has been mercifully free of time-wasters, though we do of course
get the occasional
contribution from someone outside the core group who is unaware that the feature they
want is already available.
By "implementors", I mean those participants who are actively involved in creating
implementations. I don't mean
representatives of the companies who market products, I mean the designers and developers
who actually cut the code.
Very often there are only two or three genuine developers taking part. That's not
necessarily a bad thing:
the original XQuery 1.0 work was hampered by having perhaps eight or nine people in
this role, many of
whom could have done a good job as chief designer of the language, but all of them
having different perspectives
on what kind of language they wanted to create. It tends to be the developers on the
group who come up with most
of the ideas. Ideally they not only develop implementations of the standard they are
working on, but
also have projects in which they develop applications using the technology, so they
can put themselves
in the mindset of users. They typically also have their own source of feedback from
their own
user community.
In my experience the developers on the group, although they work for companies that
are competing with each
other, often get on very well with each other: they love sharing ideas and often build
on each others' ideas
to create something that none of them would have come up with individually. This collaborative
competition
is highly beneficial to improving the state of the technology for everyone. There
can be tensions, however,
if very capable people share different visions of the end product.
All groups can suffer from having participants who are poor team players. These people
may be very
able technically, but they can get so passionate about their good ideas that they
lose any ability to
see other points of view and make compromises. They can also lose sight of the fact
that selling their ideas
is essentially a human process that depends on understanding where other people are
coming from. The chair of one standards group, who
in his day job was an industrial psychologist, once took me aside and told me that
a colleague of mine had (in my absence) presented
a proposal in such an antagonistic manner that the group rejected it out of hand,
even though the proposal
actually had considerable technical merit.
The funders — the people who pay the salaries and hotel bills of the participants
— have their own agenda, but
in my experience, they are often rather vague about what they actually want to achieve.
It's hard to convince
them that they are in a joint venture with their competitors from which everyone gains
an advantage. They may well be under the
misapprehension that by taking part, they will be able to get features into the spec
that benefit them and harm
their competitors: an argument which, in my view, is nearly always deluded. The real
business case is that the activity grows
the size of the market and they get their fair share of that growth.
Too much input from the funders can have detrimental effects. When vendors start pushing
the standard in a particular
direction, the pressure is often unrelated to any genuine understanding of user requirements.
Whether the pressure is from managers in the
vendor organization, or their marketing people, or the IT directors investing good
money in the vendor's products,
the chances are that the real needs of hands-on developers using the technology have
got lost somewhere along the way.
This can easily lead to complex features being added that no-one ends up using, while
simple
practical improvements are overlooked.
There's a contradiction I've observed in all the groups I've worked with. The fine
detail of a new feature
gets an enormous amount of detailed attention, and ends up being very well specified
and documented (far better, in my experience,
than the specification of any proprietary software product). Meanwhile,
the requirement behind the feature often receives little scrutiny. If someone claims
that their users need the feature,
it's very hard to challenge that statement; standards groups gather their requirements
from a small and self-selecting
sample of users. Certainly, I've never seen any serious attempt to quantify the cost
benefit
of a feature, or to apply any rational process to prioritization of different features.
Finally, the standards organizations: W3C, ECMA, ITU, IETF, WhatWG, or whatever. What
is their role and motivation?
Almost invariably, these groups start as a collaboration between vendors, often vendors
whose common interest is
to reduce the dominance of an existing monopoly supplier. If they are successful at
all, the dominant supplier
later senses which way the wind is blowing and joins the group. Very often the group
is formed because established
venues for doing the work have become fossilized: they have built up sufficiently
heavyweight decision-making
processes that the active parties decide they are better off starting something new.
Whether the rest of the community
likes it or not, it is implementors who drive the technology forward. User input is
useful,
but the real costs are borne by implementors, and they are only going to keep implementing
a standard if it's in their
interests to do so. There was a stage in the 1980s when official "de jure" standards
bodies became totally
disconnected from implementation activities, and it led to the creation of numerous
standards that weren't worth
the paper they were written on. As the internet sprang to life, it became clear that
implementors had the upper hand,
and that standards were often written as a post-hoc exercise once the defining products
had already become established.
That's true regardless whether the products in question were open source (like the
early email software, or like browsers)
or whether they were proprietary (like Microsoft Office).
What does all this mean for QT4? We've been fortunate. There have been no misguided
inputs from funders disconnected
from hands-on users, there's a general feeling that everyone is pulling in the right
direction, and we benefit from the reviews and comments
of a wider user community that understands the technology well and knows its limitations.
We have developed our own very
effective and economical tooling based on GitHub, XML, XSLT, Gradle, and the proprietary
DeltaXignia product (formerly DeltaXml).
The absence of a sponsoring standards organisation (unless you count the very hands-off
W3C, which makes no attempt to control
the direction) hasn't hampered us so far, though it might be useful to re-establish
a branding relationship in order to
build credibility as we come to publication stage. But we might find that at that
stage, politics creeps in.
We do have a problem knowing when to stop. We're all perfectionists who want to get
it right, and we tend to prioritize quality
over completion dates.
One of the obstacles W3C put in our way during the development of the 3.0/3.1 versions
of the standards was
the requirement to demonstrate the existence of three independent implementations.
We scraped through that requirement on XSLT 3.0: we had
two implementations actively developed by working group members (Saxon and Exselt,
the latter having since
been withdrawn from the market), and there was a third implementation, Altova Raptor,
which followed the standard
closely even though the vendor played no part in the W3C process (which in a sense
is actually good evidence that
the spec is solid). Unless there's a mystery implementor shadowing every move we make,
we're not going
to be able to satisfy that requirement for XSLT 4.0: does this matter?
My view is that a specification created using this community process is going to be
of much higher quality than
if a vendor like Saxonica had tried to go it alone, and that's what matters to the
user community.
I'm confident
that there will be other implementations in the future even it there aren't today:
at this stage of the game,
people want to see a standard set in stone before they start the expensive process
of
implementation. There are even signs that
AI technology is getting close to the point where given a good enough specification
and test suite, the process
of constructing an implementation can be largely automated. We're not there yet, but
progress has been dramatic.
Meanwhile it remains
very much the case that continuous implementation during development of the
standard is necessary both to verify that features are practically implementable,
and to provide early feedback on their usability.
And of course, the continuous and collaborative development of a comprehensive
test suite is another key ingredient - but one which probably merits a separate paper.
References
[Kay 2020]
Michael Kay.
"A Proposal for XSLT 4.0".
XML Prague, 2020.
http://archive.xmlprague.cz/2020/files/xmlprague-2020-proceedings.pdf.
[Kay 2023]
Michael Kay.
"Schema-Aware Conversion of XML to JSON".
Presented at Balisage: The Markup Conference 2022, Washington, DC, July 31 - August
4, 2023.
In Proceedings of Balisage: The Markup Conference 2023.
Balisage Series on Markup Technologies, vol. 28 (2023).
doi:https://doi.org/10.4242/BalisageVol28.Kay01.
[Kay 2025]
Michael Kay.
Kay, Michael. "JNodes: a New Model for Navigating JSON Trees".
Presented at Balisage: The Markup Conference 2025, Washington,
DC, August 4 - 8, 2025. In Proceedings of Balisage: The Markup
Conference 2025. Balisage Series on Markup Technologies, vol. 30 (2025).
doi:https://doi.org/10.4242/BalisageVol30.Kay01.
×
Michael Kay.
"Schema-Aware Conversion of XML to JSON".
Presented at Balisage: The Markup Conference 2022, Washington, DC, July 31 - August
4, 2023.
In Proceedings of Balisage: The Markup Conference 2023.
Balisage Series on Markup Technologies, vol. 28 (2023).
doi:https://doi.org/10.4242/BalisageVol28.Kay01.
×
Michael Kay.
Kay, Michael. "JNodes: a New Model for Navigating JSON Trees".
Presented at Balisage: The Markup Conference 2025, Washington,
DC, August 4 - 8, 2025. In Proceedings of Balisage: The Markup
Conference 2025. Balisage Series on Markup Technologies, vol. 30 (2025).
doi:https://doi.org/10.4242/BalisageVol30.Kay01.