docx4j and ImportXHTML 17.0.4 are now available.
To get this release, please see https://www.docx4java.org/downloads.html
It targets Java 11, and is compatible with Java 11, 17, 21, and we expect Java 25.
Both PDF/HTML
export and OpenDoPE data binding have long had non-XSLT implementations that
were faster but incomplete; in this release they reach feature parity with the
XSLT pathways and become the defaults: in
benchmarks the visitor exporters generate XSL-FO and HTML roughly an order of
magnitude faster, and the NonXSLT binding traverser was the fastest of the
three binding implementations. The previous behaviour stays one switch away:
pass Docx4J.FLAG_EXPORT_PREFER_XSL to toPDF/toHTML, or set
docx4j.model.datastorage.BindingHandler.Implementation=BindingTraverserXSLT.
Equations:
docx→HTML emits native MathML out of the box, on both pathways.
docx→PDF renders equations too: the exporters emit MathML in fo:instream-foreign-object, rendered by the JEuclid FOP plugin.
ImportXHTML: embedded MathML is now converted to native OMML
Markdown:
There's a new module: docx4j-markdown. Import and export. It
also speaks TeX math: $...$ and $$...$$ translate to native OMML equations in
both directions, for a published LaTeX subset (fractions, scripts, radicals,
n-ary operators with limits, delimiters, matrices, aligned equations and
cases, accents, and more). Facade hooks: Docx4J.fromMarkdown / Docx4J.toMarkdown.
Combined with the equation support above, this makes docx4j a clean pipeline for LLM output: markdown with math in, Word/HTML/PDF with real equations out.
OpenDoPE improvements.
- the non-XSLT implementation described above
- The same repeat control can now be used twice in one paragraph (positions are evaluated per occurrence, tracked by a new od:RptOcc param), a binding inside a repeat can address a
specific item of the repeated collection (eg .../ranks[last()]/rank), and the
reverter no longer merges adjacent expansions of the same repeat.
- There is also a security hardening: a crafted document with a cyclic condition graph
previously drove Docx4J.bind() into a StackOverflowError (a denial of
service); it is now rejected with a Docx4JException.
Plus miscellaneous fixes; full details at https://github.com/plutext/docx4j/blob/ ... ANGELOG.md

