PhoenixmlDb.XQuery 1.6.7

There is a newer version of this package available.
See the version list below for details.
dotnet add package PhoenixmlDb.XQuery --version 1.6.7
                    
NuGet\Install-Package PhoenixmlDb.XQuery -Version 1.6.7
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PhoenixmlDb.XQuery" Version="1.6.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PhoenixmlDb.XQuery" Version="1.6.7" />
                    
Directory.Packages.props
<PackageReference Include="PhoenixmlDb.XQuery" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PhoenixmlDb.XQuery --version 1.6.7
                    
#r "nuget: PhoenixmlDb.XQuery, 1.6.7"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PhoenixmlDb.XQuery@1.6.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PhoenixmlDb.XQuery&version=1.6.7
                    
Install as a Cake Addin
#tool nuget:?package=PhoenixmlDb.XQuery&version=1.6.7
                    
Install as a Cake Tool

PhoenixmlDb.XQuery

XQuery 4.0 query engine for PhoenixmlDb — query XML and JSON documents with the full power of XQuery.

Features

  • Full XQuery 4.0 — FLWOR expressions, constructors, modules, user-defined functions
  • XPath 4.0 — complete XPath implementation with 240+ built-in functions
  • JSON supportjson-doc(), parse-json(), maps, arrays — query JSON natively
  • Full-text searchft:contains() with stemming, wildcards, proximity, scoring
  • Update Facility — insert, delete, replace, rename, transform expressions
  • Type system — records, enums, union types (XQuery 4.0)

Quick example

using PhoenixmlDb.XQuery.Execution;

var engine = new QueryEngine();

// Simple query
var results = engine.ExecuteToListAsync(
    "for $x in 1 to 10 where $x mod 2 = 0 return $x * $x");

// Query XML documents
var books = engine.ExecuteAsync(
    "//book[price > 30]/title",
    containerId);
Package Description
PhoenixmlDb.Core Core types and XDM data model (dependency)
PhoenixmlDb.Xslt XSLT 4.0 transformation engine
PhoenixmlDb.XQuery.Cli xquery command-line tool

Documentation

Full documentation at phoenixml.dev

License

Apache 2.0

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on PhoenixmlDb.XQuery:

Package Downloads
PhoenixmlDb.Xslt

XSLT 4.0 transformation engine for PhoenixmlDb

Phoenixml.Platform.Editor.Xml

XML/XSD vocabulary binding for Phoenixml.Platform — concrete IDocument and ITreeNodeProvider implementations against PhoenixmlDb.Core's XDM, XSD schema validation pipeline.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.6.8 0 8/26/2026
1.6.7 113 8/24/2026
1.6.6 120 8/23/2026
1.6.5 109 8/21/2026
1.6.2 169 8/16/2026
1.6.1 184 7/31/2026
1.6.0 157 7/27/2026
1.5.5 185 7/12/2026
1.5.4 185 7/9/2026
1.5.3 133 7/8/2026
1.5.2 137 7/7/2026
1.5.1 152 6/30/2026
1.5.0 114 6/28/2026
1.4.7 147 6/25/2026
1.4.6 222 6/17/2026
1.4.5 144 6/17/2026
1.4.4 184 6/14/2026
1.4.3 137 6/10/2026
1.4.2 119 6/6/2026
1.4.1 237 5/29/2026
Loading failed

Six fixes to XPath 4.0 function behaviour, one to numeric rounding, and one new parser
option. Four came from Martin Honnen's testing; the rest from an audit prompted by his
reports, and from the conformance work that took QT3 from 76.56% to 95.11%.

### `fn:highest` and `fn:lowest` take a collation second and a key third

XPath 4.0 §14.5 declares three arguments — `$input`, `$collation`, `$key`. This engine
declared arity 1-2 with the KEY second, so `highest#3` did not exist and
`highest($seq, $key)` bound a function into the collation slot, where it was read as a
string and discarded. Reported by Martin Honnen.

Two further faults his examples could not show. Every key went through `Convert.ToDouble`,
so any non-numeric input threw an unhandled `System.FormatException` and took the process
down — `highest(("apple","banana"))` was a .NET crash, not an XQuery error. And
`highest((1,5,3), "…/collation/codepoint")` returned the right answer by accident, having
ignored the collation entirely.

### Adaptive serialization of arrays, from the `xquery` tool

`[1,2]` printed as `12`, so `partition(…)` output looked wrong when the partitioning was
correct. Martin narrowed this himself to a sequence-of-arrays serialization fault, which is
exactly what it was.

The engine's own serializer had always been right; the CLI carried a SECOND copy in which
the two runtime representations were swapped — `object?[]` (a sequence) got array brackets
while `List<object?>` (an array) was flattened. That is why the same query was correct
through `xslt` and wrong through `xquery`.

### `fn:all-equal`, `fn:all-different`, `fn:duplicate-values`

These take an optional collation as their second argument; none of the three had it, and
all three compared the *lexical form* of the atomized value, so values of different types
compared equal whenever their strings matched — `all-equal((1, "1"))` was true. Numeric
promotion is unaffected: `1`, `1.0` and `1e0` remain equal.

### `fn:QName` accepts an `xs:anyURI` namespace

F&O function conversion includes URI promotion, honoured everywhere the conversion
machinery runs. `fn:QName` hand-rolled its type check and rejected `xs:anyURI` — in exactly
the case the function exists for, since a namespace URI is the natural thing to hold in one.

### XSD regex: character-class subtraction is no longer mistaken for POSIX syntax

`[\i-[:]]` — the canonical idiom for an NCName start character, and the most common use of
subtraction anywhere — was rejected as "POSIX character class syntax is not supported",
against a pattern using no POSIX syntax at all. Both forms begin `[:`; the only thing
separating them is whether an unescaped `-` precedes the bracket.

### Schema-defined simple types as `cast` / `castable` targets

   import schema namespace s = "…" at "…xsd";
   'IB123' castable as s:restrictedString

failed with `XPST0081: Unbound namespace prefix: s`. Two causes. `import schema namespace
p = "uri"` BINDS p in the statically known namespaces (§4.11) and the prefix was extracted
into the AST and never registered — so the prefix genuinely was unbound, and every use of
it failed, not only casts. And types were modelled as a fixed enum of built-in XSD types
with no representation for a schema-defined one.

Facet validation — pattern, enumeration, length, bounds, unions, lists — is delegated to
the schema provider rather than reimplemented. `instance of` and node tests against schema
types still need typed value annotations and are not supported.

### `fn:round-half-to-even` decides ties from the binary value

   round-half-to-even(250.0250e0, 2)   gave 250.02, must be 250.03

The nearest double to 250.025 is 250.0250000000000056…, strictly above the midpoint, so it
is not a tie. `Math.Round`'s double overload applies a decimal-style correction that
manufactures ties binary does not have. Rounding is now exact integer arithmetic over the
double's mantissa and exponent, so a spurious tie is unrepresentable.

### New: `XQueryParserFacade.NormalizeLineEndings`

Defaults true, which is correct for a query file. XSLT sets it false: an XPath expression
has already been through an XML parser, where `&#xD;` inside a string literal is DATA that
XML 1.0 §2.11 exempts from line-ending normalization. Applying XQuery's query-source rule
a second time rewrote it.

### Notes

`PhoenixmlDb.Core` moves to 1.6.7 (metadata prefix `phxm` → `dbxml`, prefix only). The
`xquery` tool embeds the XSLT engine from the previous release, 1.6.6 in this train — the
CLI needs `PhoenixmlDb.Xslt` for `fn:transform` and `PhoenixmlDb.Xslt` needs
`PhoenixmlDb.XQuery`, so it trails by one by construction. The library itself depends only
on Core.

### `fn:highest` and `fn:lowest` take a collation second and a key third

XPath 4.0 §14.5 declares three arguments:

   fn:highest($input     as item()*,
              $collation as xs:string?                         := fn:default-collation(),
              $key       as (fn(item()) as xs:anyAtomicType*)? := fn:data#1) as item()*

This engine declared arity 1-2 with the KEY second, so `highest#3` did not exist and
`highest($seq, $key)` bound a function into the collation slot, where it was read as a string,
discarded, and quietly produced an unkeyed answer. Reported by Martin Honnen.

Two further faults, which his examples could not have shown:

- Every key went through `Convert.ToDouble`, so any non-numeric input threw an unhandled
 `System.FormatException` and took the process down. `highest(("apple","banana"))` was a
 .NET crash, not an XQuery error.
- `highest((1,5,3), "…/collation/codepoint")` returned `5` and looked right. It was right by
 accident: the collation cast to a function, came back null, and was ignored.

Both now go through the machinery `fn:sort` already uses, so strings, dates and mixed numerics
order correctly and the collation is honoured. Ties are unchanged — every item at the extreme
is returned, in input order.

### `fn:all-equal`, `fn:all-different` and `fn:duplicate-values` compare values

These take an optional collation as their second argument. None of the three had it, and all
three compared the *lexical form* of the atomized value, so values of different types compared
equal whenever their strings matched:

   all-equal((1, "1"))      was true    ->  now false
   all-different((1, "1"))  was false   ->  now true

Numeric promotion is unaffected: `1`, `1.0` and `1e0` remain equal. Under a collation,
`fn:duplicate-values` reports the value **as first written** rather than the later occurrence
that revealed the duplication, matching `fn:distinct-values`.

Found by auditing every collation-taking function after the `fn:highest` report. Not reported.

### `fn:partition`'s result serializes as arrays from the `xquery` tool

Adaptive output printed an array as its bare members — `12` rather than `[1,2]` — so Martin
Honnen's `partition()` example produced `12/34/56/7` where Saxon produces `[1,2]` and so on.
The partitioning itself was fixed in 1.6.6; this is the other half of the same report, which
he had suspected: "not sure whether the result is wrong or the serialization fails". Both were.

The engine's own `XQueryResultSerializer` was correct and well covered. The CLI carries a
SECOND serializer, and in it the two runtime representations were swapped: `object?[]` (a
sequence) was given array brackets, while `List<object?>` (an array) fell through to the
sequence branch and was flattened. Both directions are now corrected, and a
`PhoenixmlDb.XQuery.Cli.Tests` project exists so the tool's serializer is covered at all — it
had no tests before.

Not addressed: with `indent="yes"` Saxon breaks array members across lines and this engine
keeps them on one. The values match; the whitespace does not.