Skip to content

Releases: phax/ph-schematron

v10.0.0

Choose a tag to compare

  • New submodule ph-schematron-isosch — the SCH → XSLT preprocessing half of ph-schematron-xslt (the ISO Schematron stylesheet chain) was extracted into its own artifact.
    ph-schematron-xslt keeps only the "apply a pre-built XSLT to an XML instance" side.
    See the Migrations page for the moved classes, package locations and the Maven dependency to add.
  • New submodule ph-schematron-model — the engine-agnostic data model, the SCH XML reader/writer, the error handler types and the preprocessor were extracted from ph-schematron-pure into a much smaller artifact (no Saxon, no XPath evaluation).
    Consumers that only parse / serialize / preprocess Schematron schemas can now depend on ph-schematron-model directly.
    Packages were renamed to drop the .pure. segment — see the Migrations page for the rename table and a sed snippet to migrate imports.
  • New submodule ph-schematron-pure-xslt — pure-Java engine that generates an XSLT 3.0 stylesheet from the parsed PSSchema (no external ISO Schematron stylesheet chain) and runs it through Saxon s9api.
    Entry point SchematronResourcePureXslt accepts URIResolver, ErrorListener and a configurable XSLT version, supports <xsl:*> pass-through (xsl:function, xsl:key, xsl:include, ...) from foreign children of <sch:schema> and <xsl:choose>-bodied <sch:let>.
    Also ships SchematronToXsltConverter — a stand-alone SCH → XSLT tool that emits to a W3C DOM Document / String / OutputStream / Writer / File. The underlying PureXsltStylesheetGenerator.generate(...) returns a DOM Document so the runtime can hand it straight to Saxon XsltCompiler.compile(new DOMSource(...)) without a serialize-then-parse round trip.
    The engine's classes follow the PureXslt* naming convention (PureXsltStylesheetGenerator, PureXsltQueryBindingTransform, PureXsltTelemetry, EPureXsltVersion) so they don't clash with the ISO-XSLT engine's similarly-named types. Both wired into the Maven plugin (schematronProcessingEngine="pure-xslt") and the Ant task.
  • ph-schematron-pure-xslt version-conformant output (XSLT 1.0 / 2.0 / 3.0). EPureXsltVersion now covers XSLT 1.0, 2.0 and 3.0 (default 3.0), selectable via SchematronResourcePureXslt.builder().xsltVersion(...), SchematronPureXsltConfig and SchematronToXsltConverter.setXsltVersion(...).
    The generated stylesheet is now kept conformant to the chosen version — previously the SVRL @location was always populated with the XPath 3.0 fn:path(), so a stylesheet targeting 2.0 or 1.0 would not compile on a strict processor.
    The @location computation is now version-appropriate: fn:path() on 3.0, a generated phsch:path xsl:function on 2.0, and recursive phsch-path mode templates (no xsl:function) on 1.0.
    The XSLT 1.0 output was verified end-to-end against the JDK-bundled Xalan (XSLTC), i.e. a genuine XSLT 1.0 processor, for both non-namespaced and namespaced instances. EPureXsltVersion also gained isLT(...) / isLE(...) version-ordering helpers.
    Caveat: the built-in engine executes on Saxon-HE 12, which is an XSLT 3.0 processor — selecting 1.0 / 2.0 there only activates XSLT backwards-compatibility mode, not a true down-level engine. Whether a schema actually runs under a lower version additionally depends on the XPath used in its own test / context expressions (passed through verbatim); a queryBinding="xslt2" schema using e.g. matches() still needs a 2.0+ XPath at runtime regardless of the emitted @version.
  • Engine naming consolidated. SchematronResourcePure is now a deprecated source-compatible alias of SchematronResourcePureXPath (the canonical name; covariant setters keep chained code compiling).
    ESchematronMode is merged into ESchematronEngine — the latter now also covers the previous Mode-only XSLT_PREBUILT value and accepts every pre-v10 id (schematron, sch, schxslt-xslt2, pure-saxon, ...) as aliases.
    The Maven-plugin schematronProcessingEngine and Ant-task schematronProcessingEngine continue to accept the old strings unchanged.
  • SchematronValidationMojo now supports schxslt2. The Maven plugin's validate goal previously only handled schxslt (v1);
    selecting schematronProcessingEngine="schxslt2" now resolves to SchematronResourceSchXslt2 (SchXslt v2 / XSLT 3).
    The phaseName, languageCode and parameters parameters apply.
  • Ant task now supports schxslt2. The Ant Schematron task gained a SCHXSLT2 engine branch resolving to SchematronResourceSchXslt2 (SchXslt v2 / XSLT 3), so it now handles all six engine values (pure-xpath, pure-xslt, iso-schematron, schxslt, schxslt2, xslt) just like the validate goal. The ph-schematron-schxslt2 dependency was added to ph-schematron-ant-task.
  • ph-telemetry integration. Both SchematronResourcePureXPath and SchematronResourcePureXslt expose setTelemetry(boolean) and setPerAssertionTelemetry(boolean).
    When enabled, the engines emit OpenTelemetry-shaped spans (schematron.validate, schematron.parse, schematron.preprocess, schematron.generate, schematron.compile, schematron.execute, optional schematron.assertion), counters (schematron.assertions.failed, schematron.reports.fired, schematron.rules.fired, schematron.patterns.active) and a schematron.validate.duration histogram.
    Zero runtime cost when no ITelemetryTracerSPI / ITelemetryMeterSPI is registered — ph-telemetry degrades to no-op silently.
    Maven coordinates of ph-telemetry moved from com.helger.commons:ph-telemetry (formerly bundled with ph-commons) to the standalone repository com.helger.telemetry:ph-telemetry (current version 1.0.0-SNAPSHOT). The Java package com.helger.telemetry is unchanged, so source-level imports continue to work; only pom.xml <dependency> entries that referenced the artifact directly need their groupId updated.
  • New ph-schematron-benchmarks submodule runs the previously-test-only Main benchmarks as JMH suites.
  • Schematron edition awareness in the model (ph-schematron-model). The PS-model is now aware of which ISO/IEC 19757-3 edition each schema is targeting and can read/write/validate the full grammar of all four published editions (2006 / 2016 / 2020 / 2025). Specifically:
    • ESchematronVersion gains SCHEMATRON_2025 (with LATEST repointed at it), an getEditionYear() accessor returning the four-digit year string used by the new schematronEdition attribute, a getFromEditionYearOrNull(String) look-up, and an isOlderThan(ESchematronVersion) ordering helper.
    • PS-model elements completed. New top-level classes PSGroup, PSLibrary, PSRules, PSProperties, PSProperty. New base AbstractPSPatternLike extracted so that PSPattern and PSGroup are siblings (an instanceof PSPattern no longer matches a PSGroup). New attributes: let@as (2025), phase@from/@when (2025), rule@visit-each/@severity (2025), assert@severity and report@severity (2025), direct pattern@role/group@role (2025), pattern@documents/group@documents (2016), extends@href (2016), diagnostic@role (2020 RNC), schema-level <extends> / <param> / <rules> / <group> (2025), assert@properties/report@properties IDREFS (2016), and schema/library <properties> containers (2016). flag is now a list-of-tokens datatype (v4) — IPSHasFlag exposes getAllFlags()/addFlag(...) and setFlag(String) splits on whitespace. dir/emph/span accept the v4 dynamic group (<value-of> and <name>).
    • PSSchema.getSchematronEdition() / setSchematronEdition(...) carry the new 2025 schematronEdition attribute (typed ESchematronVersion). Reading an unrecognised attribute value emits a warning through the registered error handler.
    • Library root. PSReader.readLibrary() and readLibraryFromXML(IMicroElement) parse a <library> root document (the 2025 alternative to <schema>); PSLibrary.getAsMicroElement() writes it back.
    • Central PSVersionChecker. Walks a PSSchema and emits warnings for every feature whose introducing edition is newer than the schema's declared schematronEdition (or whenever no edition is declared). All warnings route through one private _warnFeatureUnavailable(...) method so the wording, severity or channel can be changed in a single place.
      The check is invoked automatically at the end of PSReader.readSchemaFromXML(...) and at the start of every PSWriter.write*(...) / getXMLString(...) call (the latter using an internal LoggingPSErrorHandler by default, overridable via PSWriter.setErrorHandler(...)).
      queryBinding values (xslt2, xslt3, xpath3, xpath31, xquery3, xquery31, xslt4, xpath4, xquery4, ...) are mapped to their introducing edition and flagged whenever an explicit older edition is declared.
    • Validation tightened to v4 RNC three-branch shape on PSPattern / PSGroup: is-a forbids <rule> and <let>, concrete (non-abstract / non-is-a) forbids <param>, abstract now allows <param> and <let> (newly permitted in 2025 — pre-2025 schemas using them are flagged through PSVersionChecker, not as a hard error).
  • Other v10 changes (engine renames purepure-xpath, module folder renames, ESchematronMode deprecation details, etc.) are documented in the Migrations page.

What's Changed

Full Changelog: ph-schematron-parent-pom-9.2.0...ph-schematron-parent-pom-10.0.0

v9.2.0

Choose a tag to compare

  • Updated to SchXslt2 v1.10.3
  • ph-schematron-pure migrated from JAXP XPath to the Saxon s9api. Schematron expressions are now compiled and evaluated as XPath 3.1 (default; configurable via the new EXPathVersion enum — supports 1.0 / 2.0 / 3.0 / 3.1 / 4.0). User-facing entry points (SchematronResourcePure, IPSBoundSchema, IPSValidationHandler, IPSErrorHandler) keep their DOM Node / NodeList signatures; the breaking changes are concentrated in IXPathConfig / XPathConfig / XPathConfigBuilder and in the bound-schema internals. See the Migrations wiki page.
  • (pure) XPathConfigBuilder replaces setXPathFactory(...) / setXPathFactoryClass(...) / setGlobalXPathFactory(...) / setXPathVariableResolver(...) / setXPathFunctionResolver(...) with setProcessor(Processor), setXPathVersion(EXPathVersion), addExtensionFunction(ExtensionFunction) / addAllExtensionFunctions(...), and addExternalVariable(QName, XdmValue) / addAllExternalVariables(...).
  • (pure) Custom function resolvers based on javax.xml.xpath.XPathFunction / MapBasedXPathFunctionResolver (from ph-commons) are no longer wired into the engine. Migrate by implementing net.sf.saxon.s9api.ExtensionFunction; arguments now arrive as XdmValue[] instead of List<Object> of DOM Nodes.
  • (pure) XQueryAsXPathFunctionConverter.loadXQuery(InputStream) returns ICommonsList<ExtensionFunction> instead of MapBasedXPathFunctionResolver. Feed the returned list into XPathConfigBuilder.addAllExtensionFunctions(...). The wrapper around an XQuery UserFunction now exposes the actual declared argument and result SequenceTypes, so Saxon applies the same automatic coercion (atomization, cardinality checks, type promotion) that it would for a built-in function — this fixes the long-standing DOMNodeWrapper cannot be cast to AtomicValue error when calling e.g. functx:are-distinct-values(...).
  • (pure) XPathFunctionFromUserFunction now implements ExtensionFunction (Saxon-typed throughout).
  • (pure) XPathEvaluationHelper is reshaped around XPathExecutable / XdmItem / XdmValue. Variants such as evaluateAsNodeList(...) returning DOM NodeList are gone; use evaluateAsXdmNodes(...) or evaluate(...).
  • (pure) XPathLetVariableResolver no longer implements javax.xml.xpath.XPathVariableResolver. It is now a per-thread QNameXdmValue store used internally during validation.
  • (pure) New XPathEvaluationContext (thread-local) is published as part of the SPI. The bound schema installs one per validate(...) call; the SVRL handler uses it to re-wrap DOM nodes against the same Saxon document wrapper and to read the currently-effective <let> variable bindings.
  • (pure) The bound-schema and bound-element types (PSXPathBoundSchema, PSXPathBoundRule, PSXPathBoundAssertReport, PSXPathBoundElement, PSXPathVariables, IPSXPathVariables) now hold Saxon XPathExecutable instances instead of javax.xml.xpath.XPathExpression.
  • Behavioural consequence (XPath 1.0 → 3.1). Expressions that were silently re-interpreted under XPath 1.0 (single-item conversion, implicit string coercion, eq/ne being syntax errors, etc.) now behave per the XPath 3.1 spec. Schematrons that target XPath 2.0/3.x in their queryBinding attribute work as written; Schematrons relying on XPath 1.0 quirks may need adjustment.
  • (pure) Saxon TinyTree input path. SchematronResourcePure.getAsNode(...) now parses the input XML straight into a Saxon TinyTree (via Processor.newDocumentBuilder()) and presents it as a DOM facade (net.sf.saxon.dom.NodeOverNodeInfo / DocumentOverNodeInfo). Every overload of applySchematronValidationToSVRL, getSchematronValidity and applySchematronValidation that takes a Source or IHasInputStream goes through this path. The internal validation loop short-circuits the DOM-bridge (DocumentWrapper.wrap) when it sees a Saxon-backed facade, so XPath evaluation runs directly against the TinyTree. Measured on JDK 21 against a ~1 MiB document with a representative schema, parse-only is ~28 % slower (Saxon's parser vs Xerces), validate-only is ~8 % faster, total wall-time is ~6 % faster. The win grows for more XPath-heavy schemas / repeated validations of the same document. See MainBenchmarkDomVsTinyTree in ph-schematron-pure/src/test/java. Caveats: when a custom EntityResolver is configured the TinyTree path is bypassed (so the resolver is honoured); the returned DOM facade is read-only (mutating operations throw NOT_SUPPORTED_ERR); overloads taking a pre-built org.w3c.dom.Node keep their existing behaviour.
  • (pure) <let> element bodies are now read instead of being silently discarded — fixes #189. The body text content is taken as a plain XPath expression when the value attribute is absent. XSLT-style bodies (<xsl:for-each>, <xsl:value-of> …) still cannot be evaluated by the pure engine, but instead of the cryptic <let> has no 'value' failure the user now gets a clear, actionable warning naming the offending child element. Full XSLT-body support is tracked for a future, separate Saxon-XPath-and-XSLT engine module.

What's Changed

  • Switch Schematron pure to use Saxon S9API instead of JAXP by @phax in #195

Full Changelog: ph-schematron-parent-pom-9.1.1...ph-schematron-parent-pom-9.2.0

v9.1.1

Choose a tag to compare

  • Added new enumeration ESchematronEngine to list the supported engines
  • Added new submodule ph-schematron-schxslt2 that deals with SchXslt2 (requiring XSLT 3.0 engine)
  • The Maven Plugin goal convert can now handle different Schematron engines via the new schematronEngine parameter

Full Changelog: ph-schematron-parent-pom-9.1.0...ph-schematron-parent-pom-9.1.1

ph-schematron 9.1.0

Choose a tag to compare

  • Updated to Saxon 12.9
  • Updated to ph-commons 12.1.0
  • Using JSpecify annotations

Full Changelog: ph-schematron-parent-pom-9.0.1...ph-schematron-parent-pom-9.1.0

ph-schematron 9.0.1

Choose a tag to compare

  • The XSLT based transformations use the Source based source as the basis. See #192 - thx @Lukvargen

What's Changed

  • Add support to applySchematronValidation with a source by @Lukvargen in #192

New Contributors

Full Changelog: ph-schematron-parent-pom-9.0.0...ph-schematron-parent-pom-9.0.1

ph-schematron 9.0.0

Choose a tag to compare

  • Requires Java 17 as the minimum version
  • Updated to ph-commons 12.0.0
  • Updated to Saxon 12.8

Full Changelog: ph-schematron-parent-pom-8.0.6...ph-schematron-parent-pom-9.0.0

ph-schematron 8.0.6

Choose a tag to compare

  • Updated SVRL XML Schema to support specific SchXslt elements (metadata, suppressed-rule, message-code and message-category)

Full Changelog: ph-schematron-parent-pom-8.0.5...ph-schematron-parent-pom-8.0.6

ph-schematron 8.0.5

Choose a tag to compare

  • [pure] Added method PSReader.setSchematronIncludeResolver to define a custom Schematron include resolver

Full Changelog: ph-schematron-parent-pom-8.0.4...ph-schematron-parent-pom-8.0.5

ph-schematron 8.0.4

Choose a tag to compare

  • Updated to SchXslt 1.10.1
  • The XSLT binding will emit the attribute documents for SVRL element active-pattern parallel to the previous document to ensure ISO 2016 compliance.
  • [pure] Fixed a concurrency issue with XPath variables in multi-threaded environments. See #182 and #183 - thx @bertrand-lorentz

What's Changed

Full Changelog: ph-schematron-parent-pom-8.0.3...ph-schematron-parent-pom-8.0.4

ph-schematron 8.0.3

Choose a tag to compare

  • Provided the possibility to customize the created TransformerFactory used for XSLT transformations. See #176 - thx @SvenHaul
  • [pure] Fixed variable evaluation order. See #177 and PR #178 - thx @bertrand-lorentz

What's Changed

Full Changelog: ph-schematron-parent-pom-8.0.2...ph-schematron-parent-pom-8.0.3