API Reference
Schemas and Validation
XSD schemas in XQuery, XSLT and .NET hosts: import schema, xsl:import-schema, XsdSchemaProvider, and the PhoenixmlDb.Core.Schema layer
#Schemas and Validation
The XQuery and XSLT engines compile and validate XSD 1.0 schemas through one shared layer in
PhoenixmlDb.Core, the PhoenixmlDb.Core.Schema namespace. That layer reads every schema
document, applies the limits, compiles, caches and validates, and it reports problems the same
way whichever engine asked. The layer compiles schema documents as XSD 1.0: XSD 1.1 schema
components such as assertions are not supported. The only 1.1 features the layer handles are the
vc: version-control markers and the 1.1 duration types (see XSD 1.1). A schema
that requires XSD 1.1 is refused with a message that says so. The engines themselves follow XSD
1.1 for the built-in types and regular expressions, which is why
system-property('xsl:xsd-version') is 1.1.
This page describes PhoenixmlDb.Core 2.5.0, PhoenixmlDb.XQuery 2.9.0 and PhoenixmlDb.Xslt 2.9.0.
#Contents
#Using schemas from XQuery
#In the query
import schema namespace o = "urn:example:order" at "order.xsd";
validate strict { <o:order><o:qty>3</o:qty></o:order> } instance of schema-element(o:order)
-
import schemaloads the schema when the query is compiled. A relativeathint is resolved against the query's base URI (CompilationOptions.BaseUri), not against the current directory. Each hint is tried in turn. If none loads, the error isXQST0059, and it lists why each hint failed. Under a resource policy, each hint must be allowed for import, and so must every document the schema itself includes or imports. The exception is a document that the policy's resource resolver supplies. -
Static rules come first: binding
xmlorxmlnsisXQST0070, a prefix with an empty target namespace isXQST0057, and two imports of the same namespace areXQST0058. -
validate(strict,lax, ortype) validates a node against the imported schemas.validate strictof an element that has no declaration isXQDY0084. -
validate type T { … }validates the element againstT, whatever is declared for its name, and the result has the type annotations ofTand of its content. -
An element is validated without the constraints on a document as a whole. The same ID twice, or an IDREF to no ID, does not make a validated element invalid (XQuery 3.1 §3.21.2).
Once a node has been validated, it carries its schema type:
-
data()returns values of the schema type, including restrictions, lists and unions. Atomizing a node whose type has element-only content isFOTY0012. -
Validated nodes match
element(*, p:T),schema-element(p:e)andschema-attribute(p:a), including through substitution groups. -
Each simple type the schema declares has a constructor function, and an atomic value keeps its schema type:
o:size('8') instance of o:sizeis true. Casts to schema-defined list and union types work. -
fn:idreffinds nodes that the schema types asxs:IDREForxs:IDREFS. -
A validated element of a type with element-only content has no whitespace text children (XDM 3.1 §6.2.3). Whitespace in mixed and simple content stays.
-
A nilled element (
xsi:nil="true") atomizes to the empty sequence. -
fn:distinct-valuesof validated nodes compares their typed values.
Nodes that were not validated are unaffected.
#XsdSchemaProvider
QueryEngine uses an ISchemaProvider (namespace PhoenixmlDb.XQuery) for schema features.
If you don't pass one, it creates a new, empty XsdSchemaProvider. If you pass null, schema
features are switched off.
using PhoenixmlDb.XQuery;
using PhoenixmlDb.XQuery.Execution;
var store = new XdmDocumentStore();
var engine = new QueryEngine(
nodeProvider: store,
documentResolver: store,
schemaProvider: new XsdSchemaProvider(compiledSchema)); // compiled once, see below
|
Constructor |
What it does |
|---|---|
|
|
Creates an empty provider. |
|
|
Creates a provider with these files loaded, as |
|
|
Creates a provider on a schema that the Core layer compiled. The compiled schema is shared and never changes. An |
|
Method |
Loads |
|---|---|
|
|
A schema file. |
|
|
Schema text with no location. A relative |
|
|
Same as above, from a string. |
|
|
Schema text. The documents it includes, imports or redefines are read only where |
|
|
Same as above, from a string. |
|
|
Schema text that came from |
|
|
What |
|
|
Schema text (an inline |
The overloads that take importingModule (new in 2.9.0, on ISchemaProvider as well) pass it to
the host's resolver as ResourceRequest.ModuleUri with each schema document the provider asks
for (see Resource Policy). On ISchemaProvider
each defaults to the form without the module, so a custom provider compiles unchanged.
The overloads that take no policy resolve a schema's own references with no restriction: any
file the process can read, and any URL it can reach. If you vetted the schema text but not what
it points to, use a policy overload. ResourcePolicy is in PhoenixmlDb.XQuery.Security.
var provider = new XsdSchemaProvider { PatternMatchTimeout = TimeSpan.FromSeconds(1) };
provider.AddFromString("urn:example:order", xsdText,
new Uri("file:///srv/schemas/order.xsd"), ResourcePolicy.ServerDefault);
|
Property |
Type |
Default |
Meaning |
|---|---|---|---|
|
|
|
|
Where |
|
|
|
|
Says where the documents a schema names are really read from (see XmlCatalog). What it maps a name to is still read under the load's resource policy. |
|
|
|
|
The most time one match of an |
|
|
|
|
The provider knows the schema of the XML namespace ( |
DeclaringEntities (static, 2.9.0).
XsdSchemaProvider.DeclaringEntities(IReadOnlyCollection<string> names) validates as if the
document type declaration of the document declared those entities, on the calling thread, until
the returned IDisposable is disposed. The validating parse reads no DTD, so without it every
xs:ENTITY value is "Reference to an undeclared entity". A host that read the document with its
DTD passes the names of the entities the DTD declares:
using (XsdSchemaProvider.DeclaringEntities(["logo", "banner"]))
{
// validate here
}
ValidateElementAndAnnotate (2.9.0). On ISchemaProvider and XsdSchemaProvider: validates
and annotates an element as ValidateAndAnnotate does, without the constraints on a document as a
whole (ID uniqueness, IDREF targets). The interface's default implementation applies them, as
ValidateAndAnnotate does. With a type name, ValidateXml, ValidateXmlFragment and
ValidateAndAnnotate validate against that type, whatever is declared for the element's name, and
ValidateXmlFragment validates each element of the fragment against it.
ImportCache. A schema loaded from files is compiled once and shared by every provider that
imports the same files. On each use, the cache checks the size and time of every document of
the schema, includes and imports as well as the root, and asks that use's resource policy about
each one. A changed schema file or included file is therefore seen by the next query. A schema
is cached only when all of these hold:
-
its root is a file;
-
the provider has no
Catalog; -
the policy has no resource resolver;
-
the provider holds nothing the cache did not compile.
Anything else is compiled for that provider alone.
Pattern time limits. A pattern match that runs past PatternMatchTimeout throws
RegexMatchTimeoutException from the provider's own methods. A query reports it as FOER0000. A
schema whose own enumeration, default or fixed values run past the limit is refused with
XQST0059. A query that runs with QueryExecutionLimits.RegexMatchTimeout lowers the provider's
limit, and the limit stays lowered. A provider made from a CompiledSchema can have its limit
lowered but not raised or removed.
import schema compiles its schema while the query is being compiled, before any run-time limit
applies. To bound that step, set CompilationOptions.RegexMatchTimeout:
var result = engine.Compile(query, new CompilationOptions
{
BaseUri = "file:///srv/queries/report.xq",
RegexMatchTimeout = TimeSpan.FromSeconds(1),
});
If you compile queries you didn't write, set it to the same value as
QueryExecutionLimits.RegexMatchTimeout.
#Using schemas from XSLT
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:o="urn:example:order">
<xsl:import-schema namespace="urn:example:order" schema-location="order.xsd"/>
<xsl:template name="xsl:initial-template">
<o:order xsl:validation="strict"><o:qty>2</o:qty></o:order>
</xsl:template>
</xsl:stylesheet>
-
xsl:import-schemain any module, whether imported or included, is passed toXsltTransformer.SchemaProviderwhen the stylesheet loads. A relativeschema-locationis resolved against the stylesheet's base URI. Under a resource policy, each location must be allowed for import. If none is allowed, the error isXTSE0220. -
An inline
xs:schemachild ofxsl:import-schemais read through the provider. A relativeschemaLocationinside it is relative to the stylesheet. A provider that cannot take schema text givesXTSE0220. Since 2.9.0 an inline schema with no target namespace is loaded too. -
A relative schema location in a stylesheet with no base URI is an error (2.9.0), not a location resolved against the working directory.
-
The processor is schema-aware by default (2.9.0). A
typeattribute andvalidation="strict"are accepted in a stylesheet with noxsl:import-schema, and validate against the built-in types and the schemas of the schema provider.system-property('xsl:is-schema-aware')isyes. WithXsltTransformer.SchemaAware = falsethe processor is a basic one (XSLT 3.0 §27.1): those attributes areXTSE1660in a stylesheet that has noxsl:import-schema(a bare<xsl:import-schema/>, which loads nothing, is enough to make it schema-aware).default-validationother thanpreserveorstripisXTSE0020. -
Validation is applied where the node is built (2.9.0). An element with
[xsl:]validation="strict"or"lax"built in a variable, a parameter or a function is validated there, and the variable holds the validated, annotated element.xsl:copy-ofwithvalidation="strict"or"lax"in a variable validates the copy (a document node as a document). -
Element and document constraints. A validated element is not held to the ID constraints of a document (XSLT 3.0 §25.4.1). A document node validated by
xsl:documentorxsl:result-documentmust have one element child (XTTE1550) and satisfy the ID and IDREF constraints (XTTE1555);xsl:copy-ofof a document node with validation validates it as a document (XTTE1555).xsl:result-document validation=with nohrefvalidates the principal result as a document. -
The
typeattribute validates against the type (2.9.0).typeonxsl:element,xsl:attribute,xsl:copy,xsl:copy-of,xsl:documentandxsl:result-document, andxsl:typeon a literal result element, validate the node against the named type whatever is declared for its name.type="xs:untyped"asks for no validation. -
xsl:source-document validation="strict"or"lax"validates the document it reads (2.9.0). Such a document is read into a tree and not streamed. -
The source document can be validated with
XsltTransformer.SourceValidation(see below), andinput-type-annotations="strip"removes the type annotations of a validated source. -
Constructor functions of imported schema types can be called (
o:size('8'),o:size#1), andfunction-availableanswers for them.cast as o:sizeandcastable as o:sizework.
The schema-aware typing described for XQuery applies to XPath in stylesheets. In 2.9.0 also:
-
A match pattern that names a type matches by the type:
element(*, T),element(N, T),attribute(N, T),schema-element(N)andschema-attribute(N)test the type asinstance ofdoes. Before 2.9.0 the rule matched every node of the name. -
Kind tests take their prefixes from the stylesheet, and a type name with no prefix is in the default namespace for elements and types (
xpath-default-namespace, or no namespace), so a type of a schema with no target namespace can be named (as="small",castable as small). -
as=checks derived built-in types (xs:int,xs:NMTOKEN) and atomic types a schema defines, and a typed node bound with an atomicastype keeps its type. -
xsl:value-ofof a validated node gives its typed value: an element of typexs:decimalwith the text1.10gives1.1. -
fn:copy-of,fn:snapshotandxsl:copy-of validation="preserve"keep the type annotations of what they copy. -
Typed modes:
typed="yes"refuses an element or attribute of typexs:untypedorxs:untypedAtomic(XTTE3100),typed="no"refuses a typed one (XTTE3110), andtyped="strict"refuses a rule whose pattern names an undeclared element (XTSE3105). -
json-to-xmlwithvalidate: true()gives a tree validated against the built-in schema for the XML representation of JSON.
#Validation error codes in XSLT
A validation failure in a stylesheet has the error code of XSLT (XSLT 3.0 §25.4), and
xsl:catch errors="err:XTTE1510" catches it. A validation failure is not XQDY0027 in XSLT.
|
Code |
When |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
an attribute copied with a complex |
|
|
a node not valid against its |
|
|
a new attribute validated against |
|
|
a validated document node without exactly one element child |
|
|
a validated document with duplicate IDs or an IDREF to no ID |
|
|
|
|
|
a |
|
|
|
#XsltTransformer.SchemaProvider
public PhoenixmlDb.XQuery.ISchemaProvider? SchemaProvider { get; set; }
By default this is new XsdSchemaProvider { KnowsXmlNamespace = true }, so a schema can
xs:import the XML namespace with no schemaLocation. Replace it before calling
LoadStylesheetAsync. If you set it to null, every schema-element/schema-attribute
reference becomes XPST0008 and every validation="strict" raises a run-time error.
Since 2.9.0 the default provider takes schemas from XsdSchemaProvider.ImportCache: an
xsl:import-schema from files is compiled once for all transformers and used until one of its
documents changes, under the conditions listed for ImportCache. In 2.8.0
each transformer compiled its own. A host that supplies schema documents itself can give each
transformer a provider on a CompiledSchema. An xsl:import-schema for a namespace that schema
declares is then satisfied without loading anything:
var transformer = new XsltTransformer { SchemaProvider = new XsdSchemaProvider(compiledSchema) };
await transformer.LoadStylesheetAsync(stylesheetXml);
XsltTransformer.RegexMatchTimeout is passed to the provider before the first schema import, so
it also bounds pattern facets while the stylesheet's schemas compile.
#XsltTransformer.SourceValidation
public PhoenixmlDb.Xslt.Ast.ValidationMode? SourceValidation { get; set; } // also on XsltTransformOptions
New in 2.9.0. With ValidationMode.Strict or ValidationMode.Lax, the source document is
validated against the schemas of SchemaProvider (those the stylesheet imports and any the host
added) before the transformation. A source that is not valid fails the transformation. A valid one
has the type annotations of the schema, so . instance of schema-element(o:order),
data(@n) instance of xs:integer and a mode with typed="yes" work on it. null, the default,
and the other two modes leave the source untyped. A validated source is built into a tree and not
streamed.
#XsltTransformer.PrincipalResultTree
public XsltResultTree? PrincipalResultTree { get; }
public sealed record XsltResultTree(XdmDocument Document, XdmInMemoryStore Nodes);
New in 2.9.0. After a transformation whose whole result was validated as it was built (an element
with xsl:validation, validation= or type= at its top), this is the principal result as a tree
with the type annotations validation gave it; otherwise null. The serialized result is text, and
text read again is untyped. An XQuery engine built over Nodes can evaluate expressions against
Document.
#XsltStylesheetSchema
PhoenixmlDb.Xslt.XsltStylesheetSchema (static) is the schema for XSLT 3.0 stylesheets, for a host
that wants to check a stylesheet's structure before compiling it. The W3C publishes that schema in
XSD 1.1; this is a copy an XSD 1.0 processor loads, and the file states every change made to it.
|
Member |
Meaning |
|---|---|
|
|
|
|
|
|
|
|
The schema document as a |
|
|
Opens the schema document as a |
|
|
Compiles it with |
CompiledSchema xsltSchema = XsltStylesheetSchema.Compile();
var result = SchemaValidator.Validate(xsltSchema, stylesheetText, new Uri("file:///srv/xsl/main.xsl"));
It checks less than the original: the 71 rules the original states as assertions (for example,
xsl:value-of has a select attribute or content, not both) are not checked, since XSD 1.0 has no
assertions. A stylesheet it accepts can still have a static error, and a simplified stylesheet (a
literal result element as the root) is outside what it describes.
#The Core schema layer
Hosts that compile or validate directly use the PhoenixmlDb.Core.Schema namespace (package
PhoenixmlDb.Core). A compilation has two steps:
-
Read the closure. The layer reads the roots, then every document they include, import or redefine, each one once, within the limits.
-
Compile in memory. Nothing is fetched in this step. If the compiler asks for a document that step 1 didn't read, the compilation fails.
#End-to-end example
This example compiles a schema from text, with no file or network access, validates a document against it, and prints the diagnostics.
using PhoenixmlDb.Core.Schema;
const string Xsd = """
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:example:order" xmlns="urn:example:order"
elementFormDefault="qualified">
<xs:element name="order">
<xs:complexType>
<xs:sequence>
<xs:element name="qty" type="xs:positiveInteger"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
""";
var schemaUri = new Uri("urn:example:order.xsd");
CompiledSchema schema;
try
{
schema = await SchemaCompiler.CompileAsync(
[schemaUri],
SchemaAccessGate.SuppliedOnly,
[SchemaSource.FromText(Xsd, schemaUri)]);
}
catch (SchemaCompilationException ex)
{
foreach (var diagnostic in ex.Diagnostics)
Console.WriteLine(diagnostic);
return;
}
var result = SchemaValidator.Validate(
schema,
"""<order xmlns="urn:example:order"><qty>0</qty></order>""",
new Uri("urn:example:order-1.xml"));
Console.WriteLine(result.IsValid ? "valid" : "invalid");
foreach (var diagnostic in result.Diagnostics)
Console.WriteLine($"{diagnostic.Code ?? "-"} {diagnostic}");
This prints invalid, then one error with code cvc-datatype-valid.1.2.1, located at
urn:example:order-1.xml(1,42).
#SchemaSource
SchemaSource is a schema document that the host supplies itself. It is always named by an
absolute URI. That URI is what an xs:include or xs:import elsewhere refers to it by, and
the base its own relative references resolve against. A relative URI is an ArgumentException.
|
Factory |
Use |
|---|---|
|
|
Schema text. The version token is a SHA-256 of the text. |
|
|
A manifest resource. A missing resource is an |
|
|
Content the host reads on demand, such as a schema held in a database. |
Properties: Uri, and Version (the token a compiled schema is compared by).
A document that is supplied as a source is never passed to the gate. A schema on disk or on the network needs no source: it is named by URI and read through the gate.
#ISchemaAccessGate
The gate is the only route by which the layer reads a document the host did not supply: a root
named by URI, and every xs:include, xs:import and xs:redefine in the whole closure. Nothing
in the layer opens a file or a connection itself.
public interface ISchemaAccessGate
{
string Identity { get; }
ValueTask<SchemaDocumentContent?> OpenAsync(SchemaDocumentRequest request, CancellationToken cancellationToken);
ValueTask<string?> GetVersionAsync(SchemaDocumentRequest request, CancellationToken cancellationToken);
}
-
SchemaDocumentRequest(Uri Uri, string Location, Uri? Referrer)gives the absolute URI, the location as it was written, and the referring document.IsRootis true whenReferreris null. -
OpenAsyncreturnsnew SchemaDocumentContent(stream, version), ornull. A refused document and a missing one both returnnull, so a refusal doesn't reveal whether the document exists. The layer disposes the stream. -
GetVersionAsyncreturns the version token without the content. The cache uses it. -
Identitynames the gate's rules, so that differently configured gates get separate cache entries. It does not grant access by itself. -
Within one compilation each document is opened at most once, so a gate can count opens against a budget. An exception thrown by a gate reaches the caller unchanged.
|
Gate |
Admits |
|---|---|
|
|
Nothing. A schema can be made only of the supplied |
|
|
|
The layer has no gate that fetches from the network. A host that wants one implements it.
#SchemaCompiler
ValueTask<CompiledSchema> CompileAsync(IEnumerable<Uri> roots, ISchemaAccessGate gate,
IEnumerable<SchemaSource>? sources = null, SchemaCompileOptions? options = null,
CancellationToken cancellationToken = default);
CompiledSchema Compile(IEnumerable<Uri> roots, ISchemaAccessGate gate,
IEnumerable<SchemaSource>? sources = null, SchemaCompileOptions? options = null);
Roots must be absolute URIs, and at least one is required. Compile blocks the calling thread.
Use it only when your gate and sources answer at once (files, text, resources) or when blocking a
thread is acceptable. The cancellation token is passed to the gate and the sources, and is checked
between documents. The compile step itself can't be interrupted.
Failures throw SchemaCompilationException. That includes a document that isn't available, is
too large, isn't well-formed, has a document type declaration or nests too deeply, as well as a
schema that doesn't compile. SchemaCompiler.MaxNestingDepth is 512.
CompiledSchema never changes. If its documents change, the schema is compiled again into a new instance.
|
Member |
Meaning |
|---|---|
|
|
The compiled |
|
|
The URIs the schema was requested by. |
|
|
Every document that was read, as |
|
|
Warnings from the compilation. A schema with errors is never constructed. |
|
|
The identity of the gate its documents were read through. |
|
|
The pattern limit it was compiled with, or |
#SchemaCompileOptions
A record. SchemaCompileOptions.Default is used when you pass null.
|
Property |
Type |
Default |
Meaning |
|---|---|---|---|
|
|
|
16 MiB |
The largest single schema document. The layer never takes more than this from a stream. |
|
|
|
64 MiB |
The total size of all documents in one compilation. |
|
|
|
1,024 |
The most documents one compilation may read, roots included. |
|
|
|
|
Reads a schema written for XSD 1.1 as a 1.0 processor should (see XSD 1.1). With |
|
|
|
|
Consulted for each root, for each |
|
|
|
|
The most time one match of an |
If you compile schemas you didn't write, or validate values you didn't write against patterns that
may backtrack, set PatternMatchTimeout. With a limit set, a schema whose own enumeration,
default or fixed values run past it does not compile.
#SchemaCache
SchemaCache keeps compiled schemas so that each one is compiled once and used until any
document of its closure changes, not only a root. Schemas are looked up by their roots, the
gate's identity and the compile options. A supplied SchemaSource is compared by its Version.
Every other document is checked with the gate's GetVersionAsync.
var cache = new SchemaCache(new SchemaCacheOptions { CheckInterval = TimeSpan.FromSeconds(5) });
var gate = SchemaAccessGate.LocalFiles("/srv/schemas");
CompiledSchema schema = await cache.GetAsync([new Uri("file:///srv/schemas/order.xsd")], gate);
cache.Invalidate(new Uri("file:///srv/schemas/common.xsd")); // drops every schema that uses it
|
|
Default |
Meaning |
|---|---|---|
|
|
30 seconds |
How long a cached schema is handed out without checking its documents. |
|
|
256 |
The most compiled schemas kept. The least recently used is evicted first. |
|
|
|
The clock the interval is measured by. |
|
|
Meaning |
|---|---|
|
|
Returns the cached schema if it is still current and |
|
|
The blocking form. |
|
|
Drops every compiled schema that has |
|
|
Drops every compiled schema. |
|
|
How many compiled schemas the cache holds. |
|
|
A process-wide instance. The 2.9.0 engines don't use it: |
When several requests for the same schema arrive together, it is compiled once. A failed
compilation is not kept. CheckInterval must not be negative unless it is infinite, and
MaxEntries must be at least 1. Otherwise the constructor throws ArgumentOutOfRangeException.
#SchemaValidator
SchemaValidationResult Validate(CompiledSchema schema, string instance, Uri? sourceUri = null,
SchemaValidationOptions? options = null, CancellationToken cancellationToken = default);
There are also overloads that take a TextReader or a Stream instance. sourceUri is the name
diagnostics use for the document. Any number of validations can run against one compiled schema
at once. The instance is read with no document type declaration allowed and nothing resolved.
xsi:schemaLocation, xsi:noNamespaceSchemaLocation and inline schemas in the instance are
ignored. The schema is always the one you pass in.
|
|
Default |
Meaning |
|---|---|---|
|
|
|
The document element must be declared by the schema. If it isn't, the error has code |
|
|
|
Checks |
|
|
|
Includes the schema processor's warnings with the errors. |
|
|
1,000 |
Validation stops after this many diagnostics. |
|
|
0 (no limit) |
How deeply the instance's elements may nest. Deeper is an error, and validation stops. |
|
|
Meaning |
|---|---|
|
|
True when no error was reported. Always false if validation stopped early. |
|
|
The errors, plus warnings if requested, in document order. |
|
|
Validation stopped before the end of the document: at |
|
|
A pattern match ran past the schema's |
#SchemaDiagnostic
public sealed record SchemaDiagnostic(SchemaSeverity Severity, string Message,
string? SourceUri = null, int Line = 0, int Column = 0)
{
public string? Code { get; init; }
public string? MessageId { get; init; }
}
Compilation and validation report problems in the same shape. Severity is
SchemaSeverity.Warning or SchemaSeverity.Error. Line and Column count from 1, and are 0
when unknown. ToString() gives source(line,column): error: message.
-
Codeis the XSD validation rule the diagnostic reports, such ascvc-complex-type.2.4.aorcvc-pattern-valid. It is set only for a validation error whose message maps to exactly one rule. It isnullin these cases:-
for a message that covers several rules, such as a duplicate key and a duplicate unique value;
-
for every compilation diagnostic;
-
for diagnostics the layer reports itself (except
cvc-elt.1for an undeclared document element).
-
-
MessageIdis System.Xml's own name for the message (for exampleSch_UndeclaredElement). It is the same for every diagnostic of one kind, whatever names and values the text contains. It isnullwhen unknown, and for diagnostics the layer reports itself. The names belong to System.Xml, not to this library, and they may differ between .NET versions.
Both values come from which message System.Xml raised, never from the message wording. Both are
null on a runtime where System.Xml's private state can't be read.
SchemaCompilationException (derives from XmlDbException) is thrown for a schema that
cannot be loaded or doesn't compile. Its Diagnostics property lists every error and warning, in
order.
#XmlCatalog
An OASIS XML Catalogs 1.1 catalog, used through SchemaCompileOptions.Catalog. For example, it
lets a schema that refers to http://www.w3.org/2001/xml.xsd compile from a local copy.
var catalog = await XmlCatalog.LoadAsync([new Uri("file:///srv/schemas/catalog.xml")], gate);
var options = new SchemaCompileOptions { Catalog = catalog };
-
Supported entries: all of them. That is
uri,system,public,rewriteURI,rewriteSystem,uriSuffix,systemSuffix,delegateURI,delegateSystem,delegatePublic,groupandnextCatalog, withxml:baseandpreferwhere they apply. Names are compared after the specification's normalization, and aurn:publicid:name is read as the public identifier it stands for. -
A catalog only renames. Whatever it maps a name to is still read from a source or through the gate.
-
Loading. The catalog files, and every
nextCatalogand delegated catalog, are read at load time through the same gate and sources. If one can't be read, the load fails. A loaded catalog never changes and reads nothing more. A document type declaration in a catalog file is skipped. -
Limits. At most
XmlCatalog.MaxCatalogFiles(64) files.
Members:
-
LoadAsync(catalogs, gate, sources = null, limits = null, cancellationToken = default)and the blockingLoadload a catalog. -
ResolveUri(string),ResolvePublic(string)andResolveExternalIdentifier(string?, string?)look names up. -
IdentityandDocumentsdescribe what was loaded.XmlCatalog.Emptyis a catalog with no entries.
#Characters outside the Basic Multilingual Plane
XML Schema counts characters by code point; .NET strings count UTF-16 units. Since Core 2.5.0 the layer makes facets count as XML Schema does, for a character such as an emoji or a mathematical letter:
-
Pattern facets.
., a negated class ([^a]) and a negated category (\P{L},\S,\D,\W) match one such character, not half of one. The category it belongs to (\p{L},\d,\w), and a class or range that names it, match it. A value with no such character is matched by the pattern as written. -
Length facets.
length,minLengthandmaxLengthon a type derived fromxs:stringorxs:anyURIcount characters:maxLength="1"accepts one such character. The facets of a list type (a number of items) and a binary type (a number of octets) are unchanged. A diagnostic keeps the message and rule of the facet (cvc-maxLength-valid). A schema with such facets takes about twice as long to compile; a compiled schema is cached.
A validation result can therefore change for a value that contains such characters.
#XSD 1.1
Two parts of the system use XSD, and they use different versions:
|
Part |
XSD version |
|---|---|
|
The XQuery and XSLT engines: built-in types ( |
1.1. |
|
The schema layer: compiling the schema documents a query or stylesheet imports, and validating against them |
1.0 |
So a stylesheet can see xsd-version 1.1 and still have an XSD 1.1 schema refused.
The schema processor is System.Xml's, which implements XSD 1.0. With
SchemaCompileOptions.Xsd11Compatibility (on by default):
-
Elements marked as 1.1-only with
vc:minVersion/vc:maxVersionare removed, as XSD 1.1 §4.2.2 says a 1.0 processor should do. An include that is marked 1.1-only is not fetched. -
References to
xs:dayTimeDuration,xs:yearMonthDurationandxs:dateTimeStampare read as the 1.0 types they restrict. The 1.1 type's own constraint is not applied: anxs:dayTimeDurationofP1Yis accepted. -
A rewritten document is serialized again. Line and column numbers in later diagnostics about it can therefore differ from the original.
Some schemas require XSD 1.1:
-
an
xs:schemawithvc:minVersion="1.1"; -
a schema that uses
xs:assert,xs:assertion,xs:alternative,xs:openContent,xs:defaultOpenContentorxs:overrideoutside avc:guard.
Such a schema fails with a message that names the document and the constructs:
The schema document 'urn:example:v11.xsd' requires XSD 1.1: it uses xs:assert (1) with no
vc:minVersion guard. This processor implements XSD 1.0 and reads only the parts of a schema
that are marked for it.
#Stricter than System.Xml
These defaults are stricter than a bare XmlSchemaSet or validating XmlReader. They apply to
the Core layer and so to both engines. In XQuery and XSLT, a load failure is XQST0059.
-
An unreadable include or import fails the compilation. System.Xml reports it as a warning and compiles what is left. For example, an unused
xs:importwould compile silently without its document. The message isThe schema document 'common.xsd' is not available: no source supplies it and the access gate does not admit it. -
A schema document may not have a document type declaration.
-
A schema document may not nest elements deeper than 512 levels.
-
Schema text with no base URI doesn't resolve relative locations against the current directory. Give a base URI (
SchemaSourcealways has one, and so doesXsdSchemaProvider.AddFromString(namespace, text, baseUri)). -
The document element must be declared (
RequireDeclaredRoot). Without this check, a document validated against a schema for another vocabulary would be reported valid. -
The instance's own schema hints are not followed.
xsi:schemaLocation,xsi:noNamespaceSchemaLocationand inline schemas are ignored. The instance may not have a document type declaration. -
A cached schema goes to a request only after that request's own gate has admitted every document in it. A gate object the cache hasn't seen is always asked first. After that, its answer holds for one
CheckInterval. If one gate object serves many requests and a withdrawn permission must take effect at once, setCheckIntervaltoTimeSpan.Zero, or use a separate gate object for each request.
#Known limits
-
A
CompiledSchemais not opaque. ItsXmlSchemaSetexposes every declaration, andDocumentslists each document's URI. If the code you run must not see those, don't give it the object. -
XSD 1.0 only. XSD 1.1 is limited to what XSD 1.1 describes. A 1.1 type's own constraint is not checked.
-
Pattern limits depend on System.Xml internals.
PatternMatchTimeoutworks by replacing System.Xml's compiled pattern expressions, which are private. On a runtime where they can't be reached, a schema that declares a pattern doesn't compile with a limit set, rather than running unbounded.XsdSchemaProvider.PatternMatchTimeoutthrowsNotSupportedExceptionin the same case. -
Without a pattern limit, matches are unbounded. A pattern that backtracks catastrophically takes as long as the value makes it.
-
A validated source is not streamed. A source validated with
SourceValidation, or read byxsl:source-documentwithvalidation="strict"or"lax", is built into a tree. -
No network gate is included. The layer ships
SuppliedOnlyandLocalFilesonly. -
The
LocalFilesroots must be writable only by the operator. Anyone who can write inside a root can choose what a schema is compiled from.
See also: Resource Policy · XSLT API · Queries API