fissible/transmark

A pure-PHP document conversion library: a canonical typed document model with faithful multi-level numbering resolution, and pluggable readers/writers for DOCX, Markdown, and HTML - no system binaries required.

Maintainers

Package info

github.com/fissible/transmark

pkg:composer/fissible/transmark

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 6

v0.2.0 2026-08-06 02:02 UTC

This package is auto-updated.

Last update: 2026-08-06 07:37:09 UTC


README

A pure-PHP document conversion library built around a canonical typed document model, with faithful multi-level numbering resolution and pluggable readers/writers for DOCX, Markdown, and HTML — no system binaries required.

Status: pre-alpha. The document model, numbering engine, DOCX reader, and HTML writer are implemented. Markdown support and broader node coverage remain on the roadmap. Not yet published to Packagist.

Why

Every existing open-source PHP option for DOCX → HTML conversion fails at faithfully rendering multi-level numbering (1., 7.1, (a), (i)) — including legal-outline numbering, where the numbering scheme is itself the content. PHPWord's HTML writer flattens word/numbering.xml. The tools that render numbering correctly (LibreOffice headless, Pandoc) are system binaries, which complicates Forge/Vapor/serverless deploys. Even mammoth.js, the best open-source converter available in any language, has long-standing nested-numbering bugs and deliberately drops complex formatting by design.

Transmark's bet: model the document the way Word actually does — a flat paragraph carrying a pointer into a numbering definitions table, with labels computed by a single shared engine — rather than forcing Word's numbering model into HTML's <ol>/<li> nesting. See PROJECT.md for the full design rationale.

Design at a glance

  • Canonical model, not a serialization. Every reader parses into a typed tree (DocumentBlock/Inline nodes); every writer serializes that same tree. Adding a format means writing one reader or writer, not an N×N converter.
  • Numbering is data, not markup. A numbered Paragraph holds only NumberingRef{numId, ilvl}. The rendered label ("1.1.3") is computed by NumberingEngine in a single pass and is never stored on the tree — this is what keeps a read → write round-trip convergent.
  • Legal outlines are paragraphs, not headings. Heading is reserved for true semantic section titles.
  • Semantic idempotence, not byte-for-byte. AST → format → AST should return an equivalent tree. Byte-for-byte round-tripping through DOCX or Markdown is not a goal — neither format is canonical.

HTML output conventions

Simple lists render as native nested <ol>/<ul> elements. Legal-outline numbering renders as flat paragraphs because HTML cannot express labels that concatenate counters across levels. Those paragraphs use class="numbered-paragraph legal-level-N", where N is the zero-based OOXML numbering level, so consumers can style each indentation depth.

Planned packages

  • fissible/transmark (this repo) — document model, numbering engine, DOCX/Markdown readers, HTML/Markdown writers.
  • fissible/transmark-blade — Laravel Blade adapter (separate package).
  • fissible/transmark-xlsx — XLSX reader/writer sharing this package's OOXML/zip layer.

Requirements

  • PHP 8.2+
  • ext-dom, ext-zip

Installation

Not yet published. Once tagged and released:

composer require fissible/transmark

DOCX to HTML

Readers accept document bytes and return the canonical tree; writers serialize that tree into the target format:

use Fissible\Transmark\Readers\DocxReader;
use Fissible\Transmark\Writers\HtmlWriter;

$docx = file_get_contents('/path/to/document.docx');
$document = (new DocxReader())->read($docx);
$html = (new HtmlWriter())->write($document);

DocxReader currently covers paragraphs, headings, core inline formatting, and Word numbering definitions. See the pre-alpha status above and roadmap for unsupported document features.

Contributing

See CONTRIBUTING.md for commit conventions, branching, and the TDD workflow, and PROJECT.md for the current roadmap and open issues.

Security vulnerabilities should be reported privately according to SECURITY.md, not opened as public issues.

License

MIT