Repository navigation
EN 16931 Semantic JSON 0.9.4
Added
- Pack directories:
esj validateandesj inspecttake--packs <directory>(repeatable) and
read the environment variableESJ_PACKS(a path list); every<id>/<version>/<release>/pack.json
found there joins the bundled packs and is chosen by the profile of the document. A pack with the
identity of a bundled one, and a profile two packs recognize, are refused by name — except where
those packs are releases of one pack (same id and version): then the newest release is taken,
compared part by part (3.0.10 after 3.0.9), and--packtakes another. Every report
names the origin of the pack beside its identity:syntax.pack.sourceisdirectoryand the new
syntax.pack.locationthe directory it was read from (nullfor a bundled pack), and
esj --list-packsprintsoriginfor every pack. esj packs listandesj packs fetch <recipe> --into <directory> [--replace].fetchfollows a
recipe this build carries for artefacts that may be used but not redistributed: it downloads the
files over https, refuses any whose SHA-256 is not the one the recipe pins, compiles the
Schematron to XSLT in process with the ISO Schematron XSLT 2 skeleton (MIT, now in
esj-syntax), copies the schema modules out of the bundled pack and writes a pack whose
manifest records the source URLs, the fetch date and the SHA-256 of every file. It is the only
command that opens a network connection.- The recipes
peppol-bis-billing-3.0.21andpeppol-bis-billing-3.0.20: the Peppol BIS
Billing 3.0 validation artefacts, as published by OpenPeppol — the Peppol rules for UBL and CII
and the EN 16931 Schematron that release ships (1.3.16 and 1.3.15). 3.0.21 is the May 2026
release, mandatory from 2026-08-17; OpenPeppol tagged no 3.0.21, so its recipe fetches below
the commit806866bd2bd91d7e9623b68f08164e8fbe9e67a0, never by a branch name, and a recipe
without a tag may fetch only below the commit it names.esj packs fetch peppol-bis-billing
follows the newest recipe this build carries (3.0.21);esj packs listmarks it. None of those
files is in this repository or in any artefact;esj validateon a Peppol invoice without the
pack names the command that makes it. With 3.0.21, OpenPeppol's 10 examples validateVALID
and all 62 rules its own unit tests cover fire as those tests expect; with 3.0.20, 9 examples
and 58 rules (conformance/peppol/README.md, run with-Desj.network=trueand in the JDK 21
job of the continuous integration).
Changed
-
A recipe's
source.tagis optional, with a new optionalsource.branch; the manifest of a
fetched pack records them as the recipe has them, andesj packs listnames the revision a
recipe fetches by (at tag v3.0.20,at commit … (branch 2026-Q2-QA2)). -
A PDF written by 0.9.0 to 0.9.3 still carries
invoice.esj.json. It is read as an attachment
that is not the invoice, as a logo would be:esj inspectandesj extract --listlist it
(not XML,application/json,Supplement),esj extract --attachment invoice.esj.json
hands out its bytes, andesj validatereports nothing about it. A PDF whose one attachment it
is carries no invoice (exit code 2). -
docs/java-api.mdnames Saxon-HE 13.0 as the minimum: with 12.x the XML Schema, Schematron
and XSLT path still run, and every HTML page ofesj-render, the HTML report included, fails
withAbstractMethodError(UnparsedTextURIResolver).docs/install.mdnotes that the jar
carries Saxon-HE 13.0 unrelocated.
Removed
- The ESJ document inside the hybrid PDF.
esj embedandesj render --embed ciiwrite one
embedded file, the invoice XML. Gone with the second fileinvoice.esj.json: the rule that it
and the XML are two accounts of one invoice, the option--no-esjand the line saying the
attachment went in, the container rowESJ document attachedofesj validate(lines, the
JSON membercontainer.esj, the HTML and the PDF report), the findingsPDF-ESJ-DISAGREES,
PDF-ESJ-UNSOUND,PDF-ESJ-UNREADABLE,PDF-ESJ-UNCHECKED,PDF-EMBEDDED-SEVERAL-ESJand
PDF-EMBEDDED-ESJ-LABEL, and section 15 ofSPEC.md(informative). A receiver of two
representations of one invoice has to parse and compare both; the XML is the invoice, and the
ESJ document derives from it at any time (docs/design-decisions.md). - The API of that feature, which breaks callers of it: in
esj-pdfthe classesEsjAgreement
andEsjAttachment,EmbedOptions.withEsjand theesjcomponent ofEmbedOptions(its
constructors take one argument fewer),EmbedResult.EsjOutcome,EmbedResult.esj(),
esjAttached()andesjOmitted()(its constructor takes the file and the report),
AttachmentKind.ESJ_DOCUMENT,ContainerFinding.Category.PDF_ESJand the three-argument
ContainerChecks.run; inesj-corethe phrasesPhrase.ROW_PDF_ESJ,ESJ_ATTACHMENTand
ESJ_ATTACHMENT_PARTLY.
Fixed
- UBL Credit Notes keep the sub lines of the XRechnung extension. The extension's source binds
them for UBL Invoice only, so the streaming reader dropped everycac:SubCreditNoteLine
without an observation, and the writer had no place for BG-DEX-01.ubl-creditnote.jsonnow
binds BG-DEX-01 to BG-DEX-08 and the 36 core terms a sub line reuses below
cac:CreditNoteLine//cac:SubCreditNoteLine, quantity fromcbc:CreditedQuantity(two
corrections,model/bindings/README.md). BG-DEX-09 and BT-DEX-001 to BT-DEX-003 stay unbound:
UBL 2.1 gives the credit note nocac:PrepaidPayment. Measured on
conformance/creditnote/04.01a-CREDITNOTE_ubl.xml, the KoSIT extension instance 04.01a as a
credit note: read, written, read again and accepted by the pack, with the values of the
invoice. The XSLT path (--importer xslt) still gives every sub credit note line the values
of the first credit note line, a defect of the vendored KoSIT stylesheet
(conformance/creditnote/README.md). esj-bomno longer hands on the versions the build of this project manages. The deployed POM
is flattened: no parent, no properties, and only the modules of this project in
dependencyManagement. Importing 0.9.0 to 0.9.3 also imported JUnit 6.1.3, Saxon-HE, PDFBox,
Jackson and the PostgreSQL test binaries, and so decided the JUnit version of the importing
build.
Full Changelog: v0.9.3...v0.9.4