Skip to content
lit-docx
Developer docs
Preview · unreleased

Round trips and preservation

When a DOCX is read and written back, what is rebuilt from meaning, what is kept verbatim, and what is lost.

A round trip means reading a file with parseDocx, optionally changing the LitAST, and writing it back with generateDocx. generateDocx always rebuilds the whole package from LitAST rather than patching the original ZIP, so what can be written back depends on what the LitAST holds.

Three kinds of preservation

Rebuilt from meaning

Recognized content (paragraphs, text formatting, tables, images, headers and footers, fields, content controls, comments, tracked changes and more) becomes the matching nodes, and OOXML is generated again from those nodes on write. Change the nodes and the change appears in the output file.

Elements kept verbatim

Unrecognized elements become unknownBlock (block-level) or unknownInline (inline) nodes with their original structure stored in rawXml, and are written back unchanged. rawXml is an internal serialization, not an XML string; do not edit it by hand.

Passing preserveRawXml: false when parsing drops these elements. Equations (OMML) are always kept in their original structure inside math nodes, regardless of this option.

Parts kept verbatim

These parts are stored in ast.meta.rawXmlFiles and written back unchanged:

  • Styles, numbering definitions, document settings, the font table and the theme
  • Core and custom properties
  • Comments, their extension parts and the comment people list
  • Footnotes and endnotes

Chart source data (chart parts and embedded workbooks) is also kept and written back, but charts cannot be created or edited through LitAST.

Phonetic guides

ruby writes native w:ruby, with base text in children and annotation in attrs.rubyText. Edited text or modeled properties use their current values. Unchanged ordinary run formatting, unmodeled rubyPr properties and explicit zero/false values are kept in _rubyPreservation; do not edit this internal source record. preserveRawXml: false does not disable it.

Content with relationships or range identities does not replay stale XML. A link around the whole ruby uses the shared relationship allocator; links inside either text layer violate the OOXML ruby content model and are rejected on export. Complete lifecycles for nested fields, comments and revisions remain unverified. Reopening, editing and saving were checked in Word 16.109.2; ordinary horizontal display was checked in WPS 12.1.28496. Other producers and complex combinations remain unverified; cross-producer fidelity is not guaranteed.

What is lost

The following are currently not kept through a round trip:

ContentNotes
Building blocks (glossary)Recorded in rawXmlFiles.glossaryXml when read, but not written back
Custom XML partsRecorded in ast.meta.customXmlParts when read, but not written back
Any other part not listed aboveNot copied into the output

If your use case depends on any of these, check the output file after writing.

Saving LitAST

LitAST can be saved with JSON.stringify. After JSON.parse it can still be passed to generateDocx, and verbatim content is written back with it.

lit-docx · QuireKitA DOCX parser and generator, licensed under AGPL-3.0 with a commercial option.