Guarantees and verification for perfect DOCX round-trip preservation.
1. Round-Trip Guarantee
Uniword achieves 100% round-trip fidelity for DOCX documents through complete OOXML modeling. Every OOXML element is represented as a Ruby object via lutaml-model, ensuring that load-modify-save cycles preserve all original content.
| Guarantee | Details |
|---|---|
Content preservation |
All text, formatting, and structure maintained |
Element coverage |
All 760 OOXML elements from 22 namespaces modeled |
Namespace compliance |
All required OOXML namespaces supported |
Encoding |
UTF-8 encoding maintained throughout |
Model-driven |
All XML structures represented as Ruby objects |
2. Round-Trip Example
# Load document
original = Uniword::Document.open('complex.docx')
# Modify it
original.add_paragraph("New content")
# Save back -- EVERYTHING preserved
original.save('modified.docx')
# Verify: modified.docx has ALL original content + new paragraph
3. Verified Test Results
| Test Case | Size | Nodes | Result |
|---|---|---|---|
ISO 8601-1:2019/Amd1 DOCX |
295KB |
— |
0 normative differences |
ISO 690:2021 DOCX |
4.8MB |
~130K |
0 normative differences |
ISO DIS 5878 DOCX |
29.4MB |
970K |
0 normative differences |
MHTML documents |
varies |
— |
Content preserved |
Math equations |
varies |
— |
Preserved via |
Bookmarks |
varies |
— |
ID preservation |
These results were achieved after implementing complete property coverage for paragraph, spacing, table, and section elements.
3.1. Properties Added for ISO Round-Trip Pass
The following properties were added to achieve 0 normative differences on ISO documents:
| Element | Properties |
|---|---|
ParagraphProperties |
|
Spacing |
|
TableLayout |
Converted to wrapper class with |
TableCellProperties |
|
TableRowProperties |
|
SectionProperties |
|
PageNumbering |
|
Paragraph |
|
Each Boolean property uses a BooleanElement wrapper class that correctly
round-trips the XML presence/absence pattern used by OOXML.
4. Verification with the CLI
Use the uniword verify command to validate document structure:
# Full verification (OPC + semantic)
uniword verify document.docx
# Enable XSD schema validation (slower, thorough)
uniword verify document.docx --xsd
# Machine-readable output
uniword verify document.docx --json
The verifier runs three layers of checks:
-
OPC Package — ZIP integrity, content types, relationships, part presence
-
XSD Schema — XML schema validation against 40 bundled XSD schemas
-
Word Document — 10 built-in semantic rules for cross-references, styles, numbering, footnotes, headers, bookmarks, images, tables, fonts, theme, and settings
5. Custom Validation
Register custom validation rules for domain-specific checks:
Uniword::Validation::Rules.register(MyCustomRule)
6. Profile-Driven Round-Trip
When generating new documents, provide a Profile to ensure the output matches Microsoft Word’s expected format without triggering the repair dialog:
# Load a document and save with a profile
doc = Uniword::Document.open("input.docx")
profile = Uniword::Docx::Profile.load(:word_2024_en)
doc.save("output.docx", profile: profile)
# The Reconciler populates all 11 items Word checks:
# - Content types, relationship ordering
# - Settings defaults (zoom, compat, mathPr, etc.)
# - Font table entries with full metadata
# - Style definitions (docDefaults, latentStyles)
# - Web settings, app/core properties
# - Theme, tracking attributes
7. Unmodelled parts: byte-for-byte preservation (1.4+)
Uniword models 760 OOXML elements across 22 namespaces. Parts the library does not model are preserved as raw bytes and re-emitted verbatim on save:
-
VBA projects (
vbaProject.binin.docmfiles) -
Glossary documents (
word/glossary/document.xml) -
docProps/meta.xmland other custom property parts -
customXml/items outside the standard layout -
Header and comment
.relssidecars
| Surface | Behavior |
|---|---|
|
Holds the source bytes, content type, and package path |
|
Collection of raw parts loaded from the source ZIP |
Reconciler |
Dangling-relationship sweep keeps relationships that target raw parts |
Write-time gate |
|
|
OPC-006 no longer reports false positives for raw part targets with dot segments ( |
This means .docm files round-trip without losing their macros, and documents
with embedded PDFs, OLE objects, or custom XML survive load-modify-save cycles
unchanged.
7.1. Non-compliant parts: stripped at load (1.4.2+)
The byte-for-byte preservation promise covers legitimate unmodelled parts —
those with a content type declaration (Override or Default extension match)
in [Content_Types].xml. Parts with no declaration, and no incoming
relationship, are stripped at load:
-
[trash]/*.datand similar junk drawers Word and other producers leave inside the ZIP -
OS artifacts (
_MACOSX/,.DS_Store,Thumbs.db,.*,~$*)
This matches Word’s own behavior: Word ignores such parts on open and does not write them on save.
| Configuration | Behavior |
|---|---|
|
Strip silently. Populate |
|
Don’t strip. The write-time integrity gate raises |
Strips are visible three ways:
-
Package#stripped_parts—Array<StrippedPart>(path + reason) -
Uniword.configuration.log_save_fixes = true— INFO log per strip -
uniword verifyon the source — still reports OPC-005 (verify reads the ZIP directly; it doesn’t go through the loader). Save applies cleanup; verify reports source state.
Uniword.configure do |c|
c.on_noncompliant_content = :raise # strict mode for QA pipelines
end
doc = Uniword::DocumentFactory.from_file("input.docx")
# In :strip mode, package.stripped_parts lists what was dropped
8. Write-time integrity gate (1.3+)
Every save invokes Docx::PackageIntegrityChecker after reconciliation and
before packaging. The gate refuses to write a broken package, raising
Uniword::ValidationError with structured issues:
-
missing content types
-
unresolvable relationship targets
-
dangling
r:id/r:embed/r:linkreferences -
duplicate rIds
-
malformed XML
begin
doc.save("output.docx")
rescue Uniword::ValidationError => e
e.issues.each { |i| puts "#{i.code} [#{i.part}]: #{i.message}" }
end
9. See also
-
Three-Layer Verification — the full pipeline behind
uniword verify --xsd -
Word for the command line — the master Word UI → CLI / API mapping