Document

featherdoc::Document is the root handle for a .docx package. Use it to open and save files, access body/header/footer template parts, inspect sections, and call document-wide editing APIs.

Common Tasks

Start here when you already know the workflow you need:

  • Open and save a document: use Document(path), open(), save(), and save_as(path).

  • Fill a body template: use body_template() or the document-level replace_content_control_text_by_tag(...) shortcut.

  • Work on headers or footers: use header_template(...), footer_template(...), section_header_template(...), or section_footer_template(...).

  • Edit body content directly: use paragraphs(), tables(), append_table(...), and the image append methods.

  • Inspect structure before changing it: use inspect_sections(), inspect_body_blocks(), list_bookmarks(), list_content_controls(), and last_error().

Success And Failure Semantics

Return shape

Success

Failure or no-op

std::error_code

Empty error code means the package operation completed.

Non-empty error code means the operation failed; inspect last_error() for detail and package entry context.

bool

true means the requested document XML or package metadata changed.

false means the target was unavailable, invalid, or already had no applicable change.

std::size_t

Non-zero value is the number of matched items changed or appended.

0 means no matching bookmark, content control, comment target, hyperlink, or note target was found.

std::optional<T>

Contains the requested inspection or settings value.

Empty means the section, setting, or semantic comparison could not be resolved.

Handle objects

Returned handles such as TemplatePart, Paragraph, and Table are the next editing entry point.

Check handle-specific validity rules before assuming the target exists.

Short C++ Example

featherdoc::Document doc{"template.docx"};
if (doc.open()) return 1;

doc.replace_content_control_text_by_tag("customer", "Ada");
return doc.save_as("filled.docx") ? 1 : 0;

Typed Signature Guide

Document is a package-level handle. Call open() for an existing file or create_empty() for a new package before using editing methods. Most indexes are zero-based. Path parameters are filesystem paths; text parameters are written into the resolved WordprocessingML target.

Signature

Parameters

Return semantics

explicit Document(std::filesystem::path path)

path: source or target .docx path.

Creates a handle; no package is loaded until open().

std::error_code create_empty()

None.

Empty error code means a new package was initialized.

std::error_code open()

None.

Empty error code means the current path was loaded.

std::error_code save_as(std::filesystem::path path) const

path: non-empty output .docx path.

Empty error code means the package was written to the new path.

TemplatePart body_template()

None.

Body template-part handle; check handle validity before editing.

TemplatePart header_template(std::size_t index = 0U)

index: physical header part index.

Header template-part handle for that physical part.

TemplatePart section_header_template(std::size_t section_index, section_reference_kind reference_kind = default_reference)

section_index: target section. reference_kind: default, first, or even header reference.

Template-part handle for the resolved section header.

bookmark_fill_result fill_bookmarks(std::span<const bookmark_text_binding> bindings)

bindings: bookmark-name/text pairs.

Matched, replaced, requested, and missing-bookmark counts.

std::size_t replace_content_control_text_by_tag(std::string_view tag, std::string_view replacement)

tag: content-control tag. replacement: inserted text.

Number of matching controls replaced; 0 means no match.

Table append_table(std::size_t row_count = 1U, std::size_t column_count = 1U)

row_count and column_count: initial body table shape.

New body table handle.

bool set_section_page_setup(std::size_t section_index, const section_page_setup &setup)

section_index: target section. setup: page size, margins, and orientation data.

true when section page setup was written.

std::optional<section_page_setup> get_section_page_setup(std::size_t section_index) const

section_index: target section.

Empty when the section or setup cannot be resolved.

Lifecycle

Open, create, save, and inspect the current package state.

Method

Parameters

Returns

Purpose

Document()

None.

Document

Create an empty handle; call set_path() before open().

explicit Document(std::filesystem::path path)

path: source or target .docx path.

Document

Create a handle bound to a file path.

create_empty()

None.

std::error_code

Initialize a new empty document package.

set_path(std::filesystem::path path)

path: replacement path used by open() and save().

void

Replace the current path and reset loaded package state.

path() const

None.

const std::filesystem::path &

Return the path currently bound to the handle.

open()

None.

std::error_code

Load the current .docx package with strict OPC validation.

open(const document_open_options &options)

options: validation mode and ZIP resource limits.

std::error_code

Load with the requested policy; use tolerant only for repair input.

package_diagnostics() const noexcept

None.

const std::vector<package_diagnostic> &

Return package issues, severity, entry names, and repairability recorded during tolerant open.

repair_package(const document_repair_options &options = {})

options: deterministic issue categories that may be repaired.

std::optional<package_repair_report>

Repair package state transactionally; no partial mutation occurs when an unsafe or disabled issue is present.

save() const

None.

std::error_code

Save changes back to the current path.

save_as(std::filesystem::path path) const

path: output .docx path; it must not be empty.

std::error_code

Save changes to a new path.

is_open() const

None.

bool

Return whether open() or create_empty() has loaded a package.

last_error() const noexcept

None.

const document_error_info &

Inspect the latest failure code, detail, entry_name, and optional XML offset.

enable_update_fields_on_open()

None.

bool

Add w:updateFields so Word updates fields when it opens the file.

clear_update_fields_on_open()

None.

bool

Remove the update-fields-on-open setting.

update_fields_on_open_enabled()

None.

std::optional<bool>

Inspect the update-fields-on-open setting; empty means the setting could not be read.

Open Validation And Resource Limits

The parameterless open() uses the default document_open_options. The default is package_validation_mode::strict and requires valid [Content_Types].xml, root relationships, word/document.xml, and a w:document/w:body structure. Callers repairing known legacy damage must explicitly select package_validation_mode::tolerant. Tolerant validation does not disable archive resource limits and never silently repairs the input. Inspect package_diagnostics(), call repair_package() explicitly, and write the result to a new file with save_as().

Default archive_limits allow 10,000 entries, 64 MiB per XML part, 256 MiB per binary part, 512 MiB total uncompressed data, and a compression ratio of 200. These limits are checked from ZIP metadata before extraction. Raise them only when the application has a concrete need and a trusted input boundary.

Explicit Package Repair

The default repair policy handles only deterministic changes that preserve unknown metadata: create w:body under a valid w:document, create missing root or main-document relationships, and create missing content types or correct the main-document MIME. Malformed XML, invalid roots or namespaces, duplicate main-document declarations, and external main-document relationships return package_repair_not_possible without applying other changes.

After a successful repair, save() and save_as() write a sibling temporary archive and reopen it with strict validation before replacing the target. A failed check returns package_repair_validation_failed and preserves the original. The CLI exposes inspect-package <input.docx> --json and repair-package <input.docx> --output <repaired.docx> --json.

Handle Invalidation

Paragraph, Run, Table, TableRow, TableCell, and TemplatePart are tracked, non-owning handles into the current DOM. Each handle records a package generation and a node epoch, so it neither extends the Document lifetime nor dereferences a pugixml node after the package or node has been retired.

  • set_path(...), open(...), and create_empty() reset the package and invalidate every XML-backed handle previously returned by that Document.

  • A successful repair_package(...) that changes the package replaces repaired DOM state, so previously retained XML-backed handles must be reacquired.

  • Removing a node invalidates handles to that node and all descendants.

  • Rebuilding a table, paragraph, content control, or template-part structure invalidates handles into the replaced subtree.

Use valid() for Paragraph, Run, Table, TableRow, and TableCell; use the explicit bool conversion for TemplatePart. Reads through an invalid handle return an empty result, while mutations return false or an empty handle. Unaffected sibling subtrees remain valid. Reacquire affected handles from Document or an unaffected parent.

Breaking API migration

Older releases exposed two-pugi::xml_node constructors and public set_parent / set_current methods for the XML-backed handle classes. Those entry points could not carry lifetime metadata and have been removed. Obtain handles only from Document, TemplatePart, or a parent handle; application code no longer needs direct pugixml DOM access through the public API.

Template Part Access

Use template parts when the same operation should work on body, headers, or footers.

Method

Parameters

Returns

Purpose

body_template()

None.

TemplatePart

Access the document body through the template-part API.

header_template(std::size_t index = 0U)

index: physical header part index.

TemplatePart

Access a physical header part by index.

footer_template(std::size_t index = 0U)

index: physical footer part index.

TemplatePart

Access a physical footer part by index.

section_header_template(std::size_t section_index, section_reference_kind reference_kind = default_reference)

section_index: zero-based section index. reference_kind: default, first-page, or even-page header reference.

TemplatePart

Access the resolved header for a section/reference kind.

section_footer_template(std::size_t section_index, section_reference_kind reference_kind = default_reference)

section_index: zero-based section index. reference_kind: default, first-page, or even-page footer reference.

TemplatePart

Access the resolved footer for a section/reference kind.

Sections And Inspection

Method

Parameters

Returns

Purpose

append_section(bool inherit_header_footer = true)

inherit_header_footer: copy the previous section references when true.

bool

Add a section to the end of the document.

insert_section(std::size_t section_index, bool inherit_header_footer = true)

section_index: insertion point. inherit_header_footer: copy surrounding header/footer references when true.

bool

Insert a section before an existing section.

remove_section(std::size_t section_index)

section_index: section to remove.

bool

Remove a section.

move_section(std::size_t source_section_index, std::size_t target_section_index)

source_section_index: section to move. target_section_index: destination index after removal.

bool

Reorder sections without recreating the whole document.

section_count() const noexcept

None.

std::size_t

Return the number of sections.

header_count() const noexcept / footer_count() const noexcept

None.

std::size_t

Return physical header/footer part counts.

inspect_sections()

None.

sections_inspection_summary

Return section/header/footer inspection data.

inspect_section(std::size_t section_index)

section_index: zero-based section index.

std::optional<section_inspection_summary>

Inspect one section; empty means the section is not available.

get_section_page_setup(std::size_t section_index) const

section_index: section whose setup should be read.

std::optional<section_page_setup>

Read page size, margins, orientation, and related setup.

set_section_page_setup(std::size_t section_index, const section_page_setup &setup)

section_index: target section. setup: page setup values.

bool

Apply page setup to a section.

replace_section_header_text(std::size_t section_index, std::string_view replacement_text, section_reference_kind reference_kind = default_reference)

section_index: target section. replacement_text: full header text. reference_kind: resolved header kind.

bool

Replace section header text through the resolved header part.

replace_section_footer_text(std::size_t section_index, std::string_view replacement_text, section_reference_kind reference_kind = default_reference)

section_index: target section. replacement_text: full footer text. reference_kind: resolved footer kind.

bool

Replace section footer text through the resolved footer part.

remove_section_header_reference(std::size_t section_index, section_reference_kind reference_kind = default_reference)

section_index: target section. reference_kind: header reference kind to detach.

bool

Remove the section reference only; it does not delete the physical part.

remove_section_footer_reference(std::size_t section_index, section_reference_kind reference_kind = default_reference)

section_index: target section. reference_kind: footer reference kind to detach.

bool

Remove the footer reference only; it does not delete the physical part.

inspect_body_blocks()

None.

std::vector<body_block_inspection_summary>

Inspect paragraph/table order in the body.

compare_semantic(const Document &other, document_semantic_diff_options options = {}) const

other: document to compare against. options: semantic diff toggles.

std::optional<document_semantic_diff_result>

Compare semantic document content.

Template Filling Shortcuts

These methods operate from Document directly. Use them for common template fills without first taking a TemplatePart.

Method

Parameters

Returns

Purpose

replace_bookmark_text(const std::string &bookmark_name, const std::string &replacement)

bookmark_name: bookmark to fill. replacement: text to insert.

std::size_t

Replace matching bookmark text and return the replacement count.

fill_bookmarks(std::span<const bookmark_text_binding> bindings)

bindings: bookmark/text pairs to fill in one call.

bookmark_fill_result

Fill multiple bookmarks and report requested, matched, replaced, and missing bookmarks.

fill_bookmarks(std::initializer_list<bookmark_text_binding> bindings)

bindings: inline bookmark/text pairs.

bookmark_fill_result

Fill a small bookmark set without constructing a separate container.

list_bookmarks() const / find_bookmark(std::string_view bookmark_name) const

bookmark_name: bookmark to locate for the find overload.

std::vector<bookmark_summary> / std::optional<bookmark_summary>

Inspect available bookmark slots before filling.

replace_content_control_text_by_tag(std::string_view tag, std::string_view replacement)

tag: content-control tag. replacement: text to insert.

std::size_t

Replace matching content controls and return the replacement count.

replace_content_control_text_by_alias(std::string_view alias, std::string_view replacement)

alias: content-control alias/title. replacement: text to insert.

std::size_t

Fill controls addressed by alias/title.

list_content_controls() const

None.

std::vector<content_control_summary>

Inspect content-control tags, aliases, lock state, and data binding metadata before filling.

find_content_controls_by_tag(std::string_view tag) const / find_content_controls_by_alias(std::string_view alias) const

tag or alias: lookup key for structured document tags.

std::vector<content_control_summary>

Locate fill targets before mutating the document.

replace_content_control_with_paragraphs_by_tag(std::string_view tag, const std::vector<std::string> &paragraphs)

tag: content-control tag. paragraphs: replacement paragraph text.

std::size_t

Replace matching controls with generated paragraphs.

replace_content_control_with_table_rows_by_tag(std::string_view tag, const std::vector<std::vector<std::string>> &rows)

tag: content-control tag. rows: row/cell text matrix appended as table rows.

std::size_t

Replace matching controls with rows in the surrounding table context.

replace_content_control_with_table_by_tag(std::string_view tag, const std::vector<std::vector<std::string>> &rows)

tag: content-control tag. rows: generated table matrix.

std::size_t

Replace matching controls with generated tables.

replace_content_control_with_image_by_tag(std::string_view tag, const std::filesystem::path &image_path)

tag: content-control tag. image_path: replacement image path.

std::size_t

Replace matching controls with images.

replace_content_control_with_image_by_tag(std::string_view tag, const std::filesystem::path &image_path, std::uint32_t width_px, std::uint32_t height_px)

tag: content-control tag. image_path: replacement image path. width_px / height_px: explicit image size.

std::size_t

Replace matching controls with sized images.

Body, Tables, And Images

Method

Parameters

Returns

Purpose

paragraphs()

None.

Paragraph &

Return the body paragraph iterator/editing entry.

tables()

None.

Table &

Return the body table iterator/editing entry.

append_table(std::size_t row_count = 1U, std::size_t column_count = 1U)

row_count and column_count: initial table dimensions.

Table

Append a table and return the created table handle.

append_image(const std::filesystem::path &image_path)

image_path: image to append inline.

bool

Append an inline image using natural dimensions.

append_image(const std::filesystem::path &image_path, std::uint32_t width_px, std::uint32_t height_px)

image_path: image to append. width_px / height_px: explicit image size.

bool

Append an inline image with an explicit size.

append_floating_image(const std::filesystem::path &image_path, floating_image_options options = {})

image_path: image to append. options: floating position/wrap options.

bool

Append a floating image.

append_floating_image(const std::filesystem::path &image_path, std::uint32_t width_px, std::uint32_t height_px, floating_image_options options = {})

image_path: image to append. width_px / height_px: explicit size. options: floating position/wrap options.

bool

Append a sized floating image.

Examples

Open, fill content controls, and save:

featherdoc::Document doc{"template.docx"};
if (doc.open()) {
    return 1;
}

doc.body_template().replace_content_control_text_by_tag("customer", "Ada");
return doc.save_as("filled.docx") ? 1 : 0;

Fill directly from Document and inspect failures:

featherdoc::Document doc{"template.docx"};
if (auto error = doc.open()) {
    std::cerr << doc.last_error().detail << '\n';
    return 1;
}

const auto replaced =
    doc.replace_content_control_text_by_tag("customer", "Ada");
if (replaced == 0) {
    return 1;
}

if (auto error = doc.save_as("filled.docx")) {
    std::cerr << doc.last_error().detail << '\n';
    return 1;
}

return 0;

Create a new document with a table and field-update setting:

featherdoc::Document doc;
if (doc.create_empty()) {
    return 1;
}

doc.enable_update_fields_on_open();
auto table = doc.append_table(2, 3);
if (auto customer = table.find_cell(0, 0)) {
    customer->set_text("Customer");
}
if (auto status = table.find_cell(0, 1)) {
    status->set_text("Status");
}

return doc.save_as("report.docx") ? 1 : 0;