Skip to content

DocxReader never populates WordDocument.sectionProperties from the body-level <w:sectPr> #84

Description

@ebolamerican

Title: DocxReader never populates WordDocument.sectionProperties from the body-level <w:sectPr>

Summary

DocxReader reads and then discards the document-wide <w:sectPr>. WordDocument.sectionProperties is left at its SectionProperties() defaults. Because any typed re-emission of word/document.xml rebuilds <w:sectPr> from that defaulted model, a round-trip that touches the body (insert_paragraph, add_header, …) silently collapses the section to defaults — dropping header/footer references, custom margins, page size/orientation, titlePg, pgNumType, vAlign, line numbers, and docGrid.

Root cause

In DocxReader.swift the body-child switch explicitly skips sectPr:

case "sectPr":
    // <w:sectPr> as a direct child of <w:body> is the document-wide
    // section properties block. It's parsed separately into
    // `WordDocument.sectionProperties` (not into BodyChild) — skip
    // here so it doesn't get captured as a `.rawBlockElement`.
    continue

The comment claims it is "parsed separately into WordDocument.sectionProperties", but there is no such parse — grep -n "sectionProperties =" Sources/OOXMLSwift/IO/DocxReader.swift returns nothing. The block is skipped and never read into the typed model.

Impact

Every source-loaded document that has meaningful section properties (essentially all real-world Word docs — footer references, non-default margins, letter/A4 page size, landscape sections) loses them the first time a typed edit re-emits document.xml. This is a silent data-loss bug.

Repro

  1. Open a .docx whose body <w:sectPr> has a <w:footerReference> and custom <w:pgMar>.
  2. insert_paragraph (or any typed body edit) and save.
  3. Inspect the saved word/document.xml: <w:sectPr> now carries default margins and no footer reference.

Suggested fix

Parse the body-level <w:sectPr> into WordDocument.sectionProperties in DocxReader (header/footer references by type, pgSz, pgMar, cols, titlePg, section break type, pgNumType, vAlign, lnNumType, docGrid), matching the fields the typed model can already represent. Either that, or preserve the raw <w:sectPr> verbatim and re-emit it unchanged when the typed model hasn't modified it.

Workaround in place downstream

che-word-mcp's open_document now hydrates sectionProperties from the source <w:sectPr> itself (hydrateSectionProperties) as a server-side shim. That covers the fields the typed model represents but can't recover sectPr children the model doesn't model (footnotePr, rsid attrs, exotic children) — so a proper reader-side fix is still wanted.

Environment

ooxml-swift v1.4.0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions