xquery4 2.9.0

dotnet tool install --global xquery4 --version 2.9.0
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local xquery4 --version 2.9.0
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=xquery4&version=2.9.0
                    
nuke :add-package xquery4 --version 2.9.0
                    

xquery

Command-line XQuery 3.1/4.0 processor for .NET. Query XML documents from the terminal using the PhoenixmlDb XQuery engine.

Installation

dotnet tool install -g xquery4

Usage

# Query an XML file
xquery '//book/title' library.xml

# Count elements
xquery 'count(//item)' catalog.xml

# Read from a query file
xquery -f transform.xq input.xml

# Query a directory of XML files
xquery 'collection()//product[price > 50]' ./data/

# JSON output
xquery -o json 'map { "count": count(//item) }' data.xml

# Read from stdin
cat data.xml | xquery '//item/@name'

# Show execution plan
xquery --plan 'for $x in 1 to 10 return $x * $x'

# Show timing breakdown
xquery --timing '//item' large-catalog.xml

Features

  • XQuery 3.1/4.0 — FLWOR, maps/arrays, higher-order functions, string constructors
  • Multiple output methods — adaptive, XML, text, JSON
  • Context item — input XML is available as . (standard XQuery)
  • Multiple sources — files, directories, URLs, stdin
  • Full prolog support — namespaces, variable/function declarations, serialization options
  • Execution plans — inspect how queries are compiled and optimized
  • Timing — built-in performance profiling

Documentation

Full documentation at phoenixml.dev

License

Apache-2.0

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
2.9.0 0 10/15/2026
2.8.0 71 10/9/2026
2.7.0 66 10/7/2026
2.6.0 88 10/6/2026
2.5.1 89 10/1/2026
2.4.1 90 9/28/2026
2.4.0 71 9/28/2026
2.2.0 434 9/25/2026
2.1.0 79 9/17/2026
2.0.0 83 9/15/2026
1.8.0 89 9/14/2026
1.7.0 85 9/11/2026
1.6.15 84 9/9/2026
1.6.14 98 9/7/2026
1.6.13 85 9/4/2026
1.6.12 85 9/1/2026
1.6.11 91 8/29/2026
1.6.10 90 8/29/2026
1.6.9 88 8/27/2026
1.6.8 87 8/26/2026
Loading failed

Schema-aware typing continued, module base URIs, an implicit-timezone setting, and a faster
`group by`. QT3: 207 failing of 31,331 (2.8.0: 251). Requires PhoenixmlDb.Core 2.5.0.

### API

- **The implicit timezone is a setting of the query**: `QueryEngine.ImplicitTimezone`, or
 `QueryExecutionContext.ImplicitTimezone` for one execution. It is the timezone a date, time
 or dateTime with none of its own is taken to be in (comparison, arithmetic, `order by`,
 `group by`, `distinct-values`, `min`, `max`, `adjust-*-to-timezone`), and the timezone of
 `current-dateTime()`, `current-date()`, `current-time()` and `implicit-timezone()`. Unset,
 it is the timezone of the machine as before, so nothing changes for a host that does not use
 it; `TimeSpan.Zero` gives the same answers on every machine. Queries that run at the same
 time each have their own. Needs the Core release that has `PhoenixmlDb.Xdm.ImplicitTimezone`.
- **`order by` compares dates, times and durations by value.** They were ordered as the text
 of each value: `P10D` before `P9D`, and a dateTime with no timezone before the same one with
 `Z` in every timezone.
- **`eq` on `xs:gYear`, `xs:gYearMonth`, `xs:gMonth`, `xs:gMonthDay` and `xs:gDay` uses the
 implicit timezone** for a value with none. UTC was taken, whatever the implicit timezone.
- **A host can turn `fn:transform` off**: `ResourcePolicyBuilder.AllowTransformFunction(false)`,
 read back as `ResourcePolicy.AllowTransformFunction`. It is on unless turned off, in every
 preset and with no policy at all, so nothing changes for a host that does not use it. Turned
 off, every way to call the function (by name, through a function item, `function-lookup`,
 partial application, `fn:apply`) fails with FOXT0001 before the options are read, and
 `function-lookup` does not find the function. A function of this kind implements
 `IHostGatedFunction`.
- **A schema provider is told which module imports a schema**: `ISchemaProvider.ImportSchema` and
 `AddSchemaText` have overloads that take the importing module's URI, and `XsdSchemaProvider`
 passes it to the host's resolver as `ResourceRequest.ModuleUri` with each schema document it
 asks for. Each overload defaults to the form without the module.
- **A schema provider can know the schema of the XML namespace**:
 `new XsdSchemaProvider { KnowsXmlNamespace = true }`. A schema may import that namespace with
 no `schemaLocation` (XSD 1.0 §4.2.6.2); System.Xml knows `xml:lang`, `xml:space` and
 `xml:base` of itself and not `xml:id`, so a schema with `ref="xml:id"` did not compile. Such a
 provider still takes a schema imported from files from `XsdSchemaProvider.ImportCache`. Off
 by default.
- **The host's resolver is told which module asks** (#227): a document, a text or a module that
 a query asks for comes to the resolver with `ResourceRequest.ModuleUri`, the module the
 request is written in.

### Modules

- **A library module has its own static base URI** (#223). `static-base-uri()` and a relative
 URI in a library module used the base URI of the main module.
- **An expression that a host language embeds can carry the location of its module** (#230):
 `XQueryExpression.EmbeddedInModule`. The compiler of the host language sets it (an XPath
 expression in an XSLT stylesheet), and the engine reports it to the resolver as
 `ResourceRequest.ModuleUri`.

### Schema-aware queries

- **`fn:distinct-values` of validated nodes compares their typed values**: `1.0` and `1` of
 type `xs:decimal` are one value, NOTATION values with different prefixes for one namespace
 are one value, and each item of a list counts. The string values were compared.
- **`attribute(name)` with an unprefixed name matches an attribute in no namespace only**; an
 attribute of that local name in any namespace matched.
- **An `xs:unsignedLong` above the range of `long` keeps its type**; it was a bare
 `xs:integer`, so `xs:unsignedLong('18446744073709551615') instance of xs:unsignedLong` was false.
- **`XsdSchemaProvider.DeclaringEntities(names)`** (new): validates as if the document's DTD
 declared those entities. A value of type `xs:ENTITY` names a declared entity, and the
 validating parse reads no DTD, so every such value was "Reference to an undeclared entity".
- **The typed value of a node of a NOTATION type is an `xs:NOTATION`**, an instance of its own
 type and not of `xs:QName`; no value was ever an instance of `xs:NOTATION`.
- **`fn:data`, `fn:sum`, `fn:avg`, `fn:min` and `fn:max` of nodes of a list type take each
 item of their typed values**; each node gave the whole list as one value, so
 `count(data($nodes))` counted nodes and `max` failed as "not orderable".
- **A validated element of a type with element-only content has no whitespace text
 children** (XDM 3.1 §6.2.3); they were kept. Whitespace in mixed and simple content stays.
- **An element of a union type matches `element(*, U)` and `schema-element(N)`.** Since XPath
 3.0 a node whose annotation is a member type of the union U matches `element(*, U)`; an
 element of a union type is annotated with the member its value matched, and matched
 neither. Unions within unions count too.
- **A validated attribute matches `attribute(*, T)` for a type it derives from**, as an element
 does, and every atomic type matches `xs:anyAtomicType`. Only the untyped hierarchy was known
 for attributes.
- **`schema-element(N)` with no prefix**, in a host language's expression, is in the host's
 default namespace for elements (`xpath-default-namespace` in XSLT).
- **An element is validated without the constraints on a document as a whole.** `validate` of
 an element, and `ISchemaProvider.ValidateXmlFragment`, refused an element that had the same
 ID twice or an IDREF to no ID; those constraints are for a document (XQuery 3.1 §3.21.2).
 New: `ISchemaProvider.ValidateElementAndAnnotate`.
- **A date with a negative year, or a year of more than four digits, is valid.** System.Xml
 reads a date into a DateTime, which has neither, and reported `-0055-10-10` as an invalid
 `xs:date`; a document with such a date in an `xs:date`, `xs:dateTime`, `xs:gYear` or
 `xs:gYearMonth` did not validate. XML Schema allows them.
- **`validate type T { … }` validates against the type.** The type was not used: the element
 was validated by its declaration, and an element with no declaration passed with any content
 and stayed untyped. The element is now validated against `T` whatever is declared for its
 name, and the result has the type annotations of `T` and of its content. The same holds for
 `ISchemaProvider.ValidateXml`, `ValidateXmlFragment` and `ValidateAndAnnotate` with a type
 name, which XSLT uses for its `type` attribute. QT3: 213 failing (was 222).
- **The same in a kind test**: `element(*, moneyType)` and `attribute(*, T)` with a type name
 that has no prefix, in an expression of a host language, name a type in the default
 namespace for elements and types. It was XPST0008 "unknown schema type".
- **Each element of a fragment is validated against the type** by
 `ISchemaProvider.ValidateXmlFragment` with a type name; more than one element was refused.
- **A type name with no prefix, in an expression of a host language, can name a type of an
 imported schema**: it is a type in the default namespace for elements and types, which the
 host gives (in XSLT, `xpath-default-namespace`, or no namespace). `'7' castable as small`
 was XPST0051 for a type `small` of a schema with no target namespace.
- **A kind test in an expression of a host language takes its prefixes from the host**:
 `schema-element(o:order)`, `schema-attribute(o:a)`, `element(*, o:orderType)` and
 `attribute(*, o:t)` with a prefix that the stylesheet binds. The declaration was looked for
 in no namespace, so `instance of schema-element(o:order)` was false for every element in
 XSLT, and a prefixed type name in `element(*, T)` was XPST0081.
- **A pattern facet of an imported schema counts characters by code point** (#231): `.` and a
 character class match one character outside the Basic Multilingual Plane, where they matched
 half of one. Needs the Core release that follows 2.4.0.
- **The length facets of a string type of an imported schema count characters** (#238):
 `length`, `minLength` and `maxLength` counted UTF-16 units, so `maxLength="1"` refused one
 character outside the Basic Multilingual Plane. The message of a value that is refused is the
 same as before. Needs the Core release that follows 2.4.0.
- **A nilled element atomizes to the empty sequence** (#236). An element validated with
 `xsi:nil="true"` gave the value of its type for the empty string, or an error where the
 empty string is not a value of the type.
- **A schema type is carried through in three more places** (#237): an item of a list of
 unions has the value of the first member type its text is valid for, where it stayed
 `xs:untypedAtomic`; a union with a built-in list type as a member (`xs:IDREFS`,
 `xs:NMTOKENS`, `xs:ENTITIES`) casts to it; and a variable or a context item declared as
 `schema-element(N)` accepts a validated element of that declaration.
- **`schema-element()`, `schema-attribute()` and `namespace-node()` are node types** (#233).
 A parameter declared as `schema-element(N)` was taken for an atomic type and its argument
 was atomized (FOTY0012 for an element with element-only content). The same holds for a
 declared return type, a typed `for` binding and a typed grouping key. A declared
 `schema-element(N)` return type is now matched against the schema: the name, its
 substitution group and the type annotation.

### Functions and errors

- **`file:/abs/path` is a file URI** (#229): `doc`, `doc-available` and `json-doc` threw
 `UriFormatException` for it.
- **The error of the specification where the runtime's own exception came out** (#241). A
 function of the wrong arity given to `for-each`, `filter`, `array:for-each`, `array:filter`,
 `fold-left` or `fold-right` is XPTY0004. `array:head` and `array:tail` of an empty array, and
 an array called with an index too large for an integer, are FOAY0001. An arity too large in
 a named function reference is FOAR0002. A function item as an argument of `concat` is
 FOTY0013.

### Performance

- **`group by` finds the group of a tuple by the hash of its key** (#232). Each tuple was
 compared with every group so far, so a grouping into many groups took time in proportion to
 the square of their number. It also obeys cancellation while it groups.
- **A child step from nodes that are in document order does not sort its result, and a
 predicate that is one comparison or one function call is evaluated without an iterator**
 (#239). Results are the same.

### `xquery` CLI (ships on `cli-v2.9.0`)

- Runs on **PhoenixmlDb.Xslt 2.9.0**, so `fn:transform` from a query gets the 2.9.0 engine.