Releases: phax/ph-schematron
Release list
v10.0.0
- New submodule
ph-schematron-isosch— the SCH → XSLT preprocessing half ofph-schematron-xslt(the ISO Schematron stylesheet chain) was extracted into its own artifact.
ph-schematron-xsltkeeps 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 fromph-schematron-pureinto a much smaller artifact (no Saxon, no XPath evaluation).
Consumers that only parse / serialize / preprocess Schematron schemas can now depend onph-schematron-modeldirectly.
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 parsedPSSchema(no external ISO Schematron stylesheet chain) and runs it through Saxons9api.
Entry pointSchematronResourcePureXsltacceptsURIResolver,ErrorListenerand 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 shipsSchematronToXsltConverter— a stand-alone SCH → XSLT tool that emits to a W3C DOMDocument/String/OutputStream/Writer/File. The underlyingPureXsltStylesheetGenerator.generate(...)returns a DOMDocumentso the runtime can hand it straight to SaxonXsltCompiler.compile(new DOMSource(...))without a serialize-then-parse round trip.
The engine's classes follow thePureXslt*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-xsltversion-conformant output (XSLT 1.0 / 2.0 / 3.0).EPureXsltVersionnow covers XSLT 1.0, 2.0 and 3.0 (default3.0), selectable viaSchematronResourcePureXslt.builder().xsltVersion(...),SchematronPureXsltConfigandSchematronToXsltConverter.setXsltVersion(...).
The generated stylesheet is now kept conformant to the chosen version — previously the SVRL@locationwas always populated with the XPath 3.0fn:path(), so a stylesheet targeting 2.0 or 1.0 would not compile on a strict processor.
The@locationcomputation is now version-appropriate:fn:path()on 3.0, a generatedphsch:pathxsl:functionon 2.0, and recursivephsch-pathmode templates (noxsl: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.EPureXsltVersionalso gainedisLT(...)/isLE(...)version-ordering helpers.
Caveat: the built-in engine executes on Saxon-HE 12, which is an XSLT 3.0 processor — selecting1.0/2.0there 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 owntest/contextexpressions (passed through verbatim); aqueryBinding="xslt2"schema using e.g.matches()still needs a 2.0+ XPath at runtime regardless of the emitted@version.- Engine naming consolidated.
SchematronResourcePureis now a deprecated source-compatible alias ofSchematronResourcePureXPath(the canonical name; covariant setters keep chained code compiling).
ESchematronModeis merged intoESchematronEngine— the latter now also covers the previous Mode-onlyXSLT_PREBUILTvalue and accepts every pre-v10 id (schematron,sch,schxslt-xslt2,pure-saxon, ...) as aliases.
The Maven-pluginschematronProcessingEngineand Ant-taskschematronProcessingEnginecontinue to accept the old strings unchanged. SchematronValidationMojonow supportsschxslt2. The Maven plugin'svalidategoal previously only handledschxslt(v1);
selectingschematronProcessingEngine="schxslt2"now resolves toSchematronResourceSchXslt2(SchXslt v2 / XSLT 3).
ThephaseName,languageCodeandparametersparameters apply.- Ant task now supports
schxslt2. The AntSchematrontask gained aSCHXSLT2engine branch resolving toSchematronResourceSchXslt2(SchXslt v2 / XSLT 3), so it now handles all six engine values (pure-xpath,pure-xslt,iso-schematron,schxslt,schxslt2,xslt) just like thevalidategoal. Theph-schematron-schxslt2dependency was added toph-schematron-ant-task. ph-telemetryintegration. BothSchematronResourcePureXPathandSchematronResourcePureXsltexposesetTelemetry(boolean)andsetPerAssertionTelemetry(boolean).
When enabled, the engines emit OpenTelemetry-shaped spans (schematron.validate,schematron.parse,schematron.preprocess,schematron.generate,schematron.compile,schematron.execute, optionalschematron.assertion), counters (schematron.assertions.failed,schematron.reports.fired,schematron.rules.fired,schematron.patterns.active) and aschematron.validate.durationhistogram.
Zero runtime cost when noITelemetryTracerSPI/ITelemetryMeterSPIis registered — ph-telemetry degrades to no-op silently.
Maven coordinates ofph-telemetrymoved fromcom.helger.commons:ph-telemetry(formerly bundled with ph-commons) to the standalone repositorycom.helger.telemetry:ph-telemetry(current version1.0.0-SNAPSHOT). The Java packagecom.helger.telemetryis unchanged, so source-level imports continue to work; onlypom.xml<dependency>entries that referenced the artifact directly need theirgroupIdupdated.- New
ph-schematron-benchmarkssubmodule 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:ESchematronVersiongainsSCHEMATRON_2025(withLATESTrepointed at it), angetEditionYear()accessor returning the four-digit year string used by the newschematronEditionattribute, agetFromEditionYearOrNull(String)look-up, and anisOlderThan(ESchematronVersion)ordering helper.- PS-model elements completed. New top-level classes
PSGroup,PSLibrary,PSRules,PSProperties,PSProperty. New baseAbstractPSPatternLikeextracted so thatPSPatternandPSGroupare siblings (aninstanceof PSPatternno longer matches aPSGroup). New attributes:let@as(2025),phase@from/@when(2025),rule@visit-each/@severity(2025),assert@severityandreport@severity(2025), directpattern@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@propertiesIDREFS (2016), andschema/library<properties>containers (2016).flagis now a list-of-tokens datatype (v4) —IPSHasFlagexposesgetAllFlags()/addFlag(...)andsetFlag(String)splits on whitespace.dir/emph/spanaccept the v4 dynamic group (<value-of>and<name>). PSSchema.getSchematronEdition()/setSchematronEdition(...)carry the new 2025schematronEditionattribute (typedESchematronVersion). Reading an unrecognised attribute value emits a warning through the registered error handler.- Library root.
PSReader.readLibrary()andreadLibraryFromXML(IMicroElement)parse a<library>root document (the 2025 alternative to<schema>);PSLibrary.getAsMicroElement()writes it back. - Central
PSVersionChecker. Walks aPSSchemaand emits warnings for every feature whose introducing edition is newer than the schema's declaredschematronEdition(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 ofPSReader.readSchemaFromXML(...)and at the start of everyPSWriter.write*(...)/getXMLString(...)call (the latter using an internalLoggingPSErrorHandlerby default, overridable viaPSWriter.setErrorHandler(...)).
queryBindingvalues (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 throughPSVersionChecker, not as a hard error).
- Other v10 changes (engine renames
pure→pure-xpath, module folder renames,ESchematronModedeprecation 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
- Updated to SchXslt2 v1.10.3
ph-schematron-puremigrated from JAXP XPath to the Saxon s9api. Schematron expressions are now compiled and evaluated as XPath 3.1 (default; configurable via the newEXPathVersionenum — supports1.0/2.0/3.0/3.1/4.0). User-facing entry points (SchematronResourcePure,IPSBoundSchema,IPSValidationHandler,IPSErrorHandler) keep their DOMNode/NodeListsignatures; the breaking changes are concentrated inIXPathConfig/XPathConfig/XPathConfigBuilderand in the bound-schema internals. See the Migrations wiki page.- (pure)
XPathConfigBuilderreplacessetXPathFactory(...)/setXPathFactoryClass(...)/setGlobalXPathFactory(...)/setXPathVariableResolver(...)/setXPathFunctionResolver(...)withsetProcessor(Processor),setXPathVersion(EXPathVersion),addExtensionFunction(ExtensionFunction)/addAllExtensionFunctions(...), andaddExternalVariable(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 implementingnet.sf.saxon.s9api.ExtensionFunction; arguments now arrive asXdmValue[]instead ofList<Object>of DOMNodes. - (pure)
XQueryAsXPathFunctionConverter.loadXQuery(InputStream)returnsICommonsList<ExtensionFunction>instead ofMapBasedXPathFunctionResolver. Feed the returned list intoXPathConfigBuilder.addAllExtensionFunctions(...). The wrapper around an XQueryUserFunctionnow exposes the actual declared argument and resultSequenceTypes, so Saxon applies the same automatic coercion (atomization, cardinality checks, type promotion) that it would for a built-in function — this fixes the long-standingDOMNodeWrapper cannot be cast to AtomicValueerror when calling e.g.functx:are-distinct-values(...). - (pure)
XPathFunctionFromUserFunctionnow implementsExtensionFunction(Saxon-typed throughout). - (pure)
XPathEvaluationHelperis reshaped aroundXPathExecutable/XdmItem/XdmValue. Variants such asevaluateAsNodeList(...)returning DOMNodeListare gone; useevaluateAsXdmNodes(...)orevaluate(...). - (pure)
XPathLetVariableResolverno longer implementsjavax.xml.xpath.XPathVariableResolver. It is now a per-threadQName→XdmValuestore used internally during validation. - (pure) New
XPathEvaluationContext(thread-local) is published as part of the SPI. The bound schema installs one pervalidate(...)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 SaxonXPathExecutableinstances instead ofjavax.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/nebeing syntax errors, etc.) now behave per the XPath 3.1 spec. Schematrons that target XPath 2.0/3.x in theirqueryBindingattribute 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 (viaProcessor.newDocumentBuilder()) and presents it as a DOM facade (net.sf.saxon.dom.NodeOverNodeInfo/DocumentOverNodeInfo). Every overload ofapplySchematronValidationToSVRL,getSchematronValidityandapplySchematronValidationthat takes aSourceorIHasInputStreamgoes 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. SeeMainBenchmarkDomVsTinyTreeinph-schematron-pure/src/test/java. Caveats: when a customEntityResolveris configured the TinyTree path is bypassed (so the resolver is honoured); the returned DOM facade is read-only (mutating operations throwNOT_SUPPORTED_ERR); overloads taking a pre-builtorg.w3c.dom.Nodekeep 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 thevalueattribute 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
Full Changelog: ph-schematron-parent-pom-9.1.1...ph-schematron-parent-pom-9.2.0
v9.1.1
- Added new enumeration
ESchematronEngineto list the supported engines - Added new submodule
ph-schematron-schxslt2that deals with SchXslt2 (requiring XSLT 3.0 engine) - The Maven Plugin goal
convertcan now handle different Schematron engines via the newschematronEngineparameter
Full Changelog: ph-schematron-parent-pom-9.1.0...ph-schematron-parent-pom-9.1.1
ph-schematron 9.1.0
- 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
- The XSLT based transformations use the
Sourcebased source as the basis. See #192 - thx @Lukvargen
What's Changed
- Add support to applySchematronValidation with a source by @Lukvargen in #192
New Contributors
- @Lukvargen made their first contribution in #192
Full Changelog: ph-schematron-parent-pom-9.0.0...ph-schematron-parent-pom-9.0.1
ph-schematron 9.0.0
- 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
- Updated SVRL XML Schema to support specific SchXslt elements (
metadata,suppressed-rule,message-codeandmessage-category)
Full Changelog: ph-schematron-parent-pom-8.0.5...ph-schematron-parent-pom-8.0.6
ph-schematron 8.0.5
- [pure] Added method
PSReader.setSchematronIncludeResolverto 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
- Updated to SchXslt 1.10.1
- The XSLT binding will emit the attribute
documentsfor SVRL elementactive-patternparallel to the previousdocumentto 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
- Fix variable values thread safety in pure mode by @bertrand-lorentz in #183
Full Changelog: ph-schematron-parent-pom-8.0.3...ph-schematron-parent-pom-8.0.4
ph-schematron 8.0.3
- Provided the possibility to customize the created
TransformerFactoryused for XSLT transformations. See #176 - thx @SvenHaul - [pure] Fixed variable evaluation order. See #177 and PR #178 - thx @bertrand-lorentz
What's Changed
- pure: Evaluate variables in the order they are declared by @bertrand-lorentz in #178
Full Changelog: ph-schematron-parent-pom-8.0.2...ph-schematron-parent-pom-8.0.3