Document¶
featherdoc::Document 是 .docx 文档包的根对象。通常先用它打开或创建
文档,再通过正文、页眉、页脚、分节和检查 API 完成编辑与验证。
常用任务入口¶
已经知道目标工作流时,可以从这里开始:
打开和保存文档:使用
Document(path)、open()、save()和save_as(path)。填充正文模板:使用
body_template(),或直接调用文档级replace_content_control_text_by_tag(...)快捷入口。修改页眉或页脚:使用
header_template(...)、footer_template(...)、section_header_template(...)或section_footer_template(...)。直接编辑正文内容:使用
paragraphs()、tables()、append_table(...)和图片追加方法。修改前检查结构:使用
inspect_sections()、inspect_body_blocks()、list_bookmarks()、list_content_controls()和last_error()。
成功/失败语义¶
返回形态 |
成功含义 |
失败或无变化含义 |
|---|---|---|
|
空错误码表示包操作完成。 |
非空错误码表示操作失败;用 |
|
|
|
|
非零值表示匹配并修改或追加的项目数量。 |
|
|
包含请求的检查结果或设置值。 |
空值表示分节、设置或语义对比结果无法解析。 |
句柄对象 |
返回的 |
使用前应按对应对象页的有效性规则确认目标存在。 |
短 C++ 示例¶
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;
类型化签名导读¶
Document 是文档包级句柄。处理已有文件时先调用 open(),创建新包时
先调用 create_empty(),再使用编辑方法。大多数下标都从 0 开始。路径参数
表示文件系统路径;文本参数会写入解析后的 WordprocessingML 目标。
签名 |
参数 |
返回语义 |
|---|---|---|
|
|
创建句柄;调用 |
|
无。 |
空错误码表示新文档包已初始化。 |
|
无。 |
空错误码表示当前路径已加载。 |
|
|
空错误码表示文档包已写入新路径。 |
|
无。 |
返回正文模板部件句柄;编辑前应检查句柄有效性。 |
|
|
返回该物理部件的页眉模板部件句柄。 |
|
|
返回解析后的分节页眉模板部件句柄。 |
|
|
返回匹配、替换、请求和缺失书签统计。 |
|
|
返回被替换的匹配控件数量; |
|
|
返回新建的正文表格句柄。 |
|
|
分节页面设置写入成功时返回 |
|
|
分节或页面设置无法解析时返回空值。 |
生命周期¶
用于打开、创建、保存文档,并检查当前包状态。
方法 |
参数 |
返回值 |
用途 |
|---|---|---|---|
|
无。 |
|
创建空句柄;调用 |
|
|
|
创建绑定到指定路径的文档句柄。 |
|
无。 |
|
初始化一个新的空 |
|
|
|
替换当前路径,并重置已经加载的包状态。 |
|
无。 |
|
返回当前绑定路径。 |
|
无。 |
|
以严格 OPC 校验加载当前路径对应的 |
|
|
|
按指定策略加载文档;仅在修复历史损坏包时选择 |
|
无。 |
|
返回宽容打开期间发现的包结构问题、严重度、部件名和可修复标记。 |
|
|
|
事务式修复内存中的包结构;遇到不安全或被选项禁用的问题时不做部分修改。 |
|
无。 |
|
将修改保存回当前路径。 |
|
|
|
将修改另存为新路径。 |
|
无。 |
|
判断 |
|
无。 |
|
查看最近一次失败的 |
|
无。 |
|
写入 |
|
无。 |
|
清除“打开时更新域”的设置。 |
|
无。 |
|
检查“打开时更新域”设置;为空表示当前无法读取该设置。 |
打开校验与资源限制¶
无参数 open() 等价于传入默认 document_open_options。默认使用
package_validation_mode::strict,并要求 [Content_Types].xml、根关系、
word/document.xml 和 w:document/w:body 结构有效。需要读取历史损坏包做
修复时,调用方必须显式选择 package_validation_mode::tolerant;宽容模式不会
关闭 ZIP 资源限制,也不会静默修改文档。调用方应读取 package_diagnostics(),
再显式调用 repair_package(),并使用 save_as() 写入新文件。
默认 archive_limits 为 10,000 个条目、单个 XML 64 MiB、单个二进制部件
256 MiB、总解压量 512 MiB、最大压缩比 200。限制在解压前依据 ZIP metadata
检查。业务确有需要时可以调高,但应保留与输入来源相匹配的上限。
显式包修复¶
默认修复策略只处理能够确定恢复且不会覆盖未知元数据的问题:在合法
w:document 下补建 w:body,补建缺失的根关系或主文档关系,以及补建缺失的
[Content_Types].xml 或修正主文档 MIME。已有 XML 损坏、根节点/namespace
错误、重复主文档声明和 external 主文档关系会返回
package_repair_not_possible,不会先修改其他部件。
修复成功后,save()/save_as() 会先把结果写入同目录临时文件,再用 strict
模式重新打开该临时包;复验失败返回 package_repair_validation_failed,原目标
保持不变。CLI 可使用 inspect-package <input.docx> --json 查看诊断,使用
repair-package <input.docx> --output <repaired.docx> --json 安全地另存修复结果。
句柄失效规则¶
Paragraph、Run、Table、TableRow、TableCell 和
TemplatePart 等对象是指向当前 DOM 的受跟踪非拥有句柄。句柄同时记录包级
generation 和节点级 epoch;因此它不会延长 Document 生命周期,也不会在
DOM 已重置或节点已删除后继续解引用悬空的 pugixml 节点。
set_path(...)、open(...)和create_empty()会重置整个包,因此使 该Document先前返回的全部 XML 句柄失效。成功且实际发生修改的
repair_package(...)会替换被修复的 DOM,因此也必须 重新获取此前保存的 XML-backed 句柄。删除节点会使该节点及其后代句柄失效。
表格、段落、内容控件或模板部件的结构重建,会使被替换子树上的句柄失效。
Paragraph、Run、Table、TableRow 和 TableCell 可通过
valid() 检查;TemplatePart 使用显式 bool 转换检查。失效句柄的读取
返回空结果,修改返回 false 或空句柄,不会访问已释放内存。未被删除的兄弟
子树保持有效。完成上述操作后,应从 Document 或仍有效的父级入口重新获取
需要继续使用的句柄。
破坏性 API 迁移说明¶
旧版允许调用方用两个 pugi::xml_node 直接构造 Paragraph、Run、
Table、TableRow 或 TableCell,也公开了 set_parent /
set_current。这些入口无法携带生命周期信息,现已彻底删除。调用方应只从
Document、TemplatePart 或父级句柄获取子句柄;公开 API 不再要求业务
代码直接依赖 pugixml DOM。
模板部件入口¶
当同一类操作需要作用在正文、页眉或页脚上时,优先使用模板部件入口。
方法 |
参数 |
返回值 |
用途 |
|---|---|---|---|
|
无。 |
|
通过模板部件 API 访问正文。 |
|
|
|
按物理页眉部件下标访问页眉。 |
|
|
|
按物理页脚部件下标访问页脚。 |
|
|
|
访问某个分节和引用类型解析后的页眉。 |
|
|
|
访问某个分节和引用类型解析后的页脚。 |
分节与检查¶
方法 |
参数 |
返回值 |
用途 |
|---|---|---|---|
|
|
|
在文档末尾追加分节。 |
|
|
|
在指定分节前插入新分节。 |
|
|
|
删除指定分节。 |
|
|
|
在不重建整篇文档的情况下调整分节顺序。 |
|
无。 |
|
返回分节数量。 |
|
无。 |
|
返回物理页眉/页脚部件数量。 |
|
无。 |
|
返回分节、页眉和页脚检查结果。 |
|
|
|
检查单个分节;为空表示目标分节不可用。 |
|
|
|
读取页面尺寸、页边距、方向等页面设置。 |
|
|
|
将页面设置应用到指定分节。 |
|
|
|
替换指定分节解析后的页眉文本。 |
|
|
|
替换指定分节解析后的页脚文本。 |
|
|
|
只移除分节引用,不删除物理页眉部件。 |
|
|
|
只移除页脚引用,不删除物理页脚部件。 |
|
无。 |
|
检查正文中段落和表格的顺序。 |
|
|
|
比较两个文档的语义内容差异。 |
模板填充快捷入口¶
这些方法直接从 Document 操作。常见模板填充场景不必先取得
TemplatePart。
方法 |
参数 |
返回值 |
用途 |
|---|---|---|---|
|
|
|
替换匹配书签文本,并返回替换数量。 |
|
|
|
批量填充书签,并报告 requested、matched、replaced 和缺失书签。 |
|
|
|
不额外构造容器时填充少量书签。 |
|
|
|
填充前检查可用书签槽位。 |
|
|
|
替换匹配内容控件,并返回替换数量。 |
|
|
|
按 alias/title 填充内容控件。 |
|
无。 |
|
填充前检查内容控件 tag、alias、锁定状态和数据绑定信息。 |
|
|
|
修改文档前定位要填充的内容控件。 |
|
|
|
将匹配内容控件替换为生成段落。 |
|
|
|
在周围表格上下文中将匹配内容控件替换为表格行。 |
|
|
|
将匹配内容控件替换为生成表格。 |
|
|
|
将匹配内容控件替换为图片。 |
|
|
|
将匹配内容控件替换为指定尺寸图片。 |
正文、表格和图片¶
方法 |
参数 |
返回值 |
用途 |
|---|---|---|---|
|
无。 |
|
返回正文段落迭代/编辑入口。 |
|
无。 |
|
返回正文表格迭代/编辑入口。 |
|
|
|
追加表格并返回新建表格句柄。 |
|
|
|
按图片自然尺寸追加行内图片。 |
|
|
|
按指定尺寸追加行内图片。 |
|
|
|
追加浮动图片。 |
|
|
|
追加指定尺寸的浮动图片。 |
批注、修订和链接¶
详细能力在对应对象页中展开;这里列出 Document 级常用入口。
方法 |
参数 |
返回值 |
用途 |
|---|---|---|---|
|
|
|
添加批注;成功返回 |
|
|
|
给段落内精确文本范围添加批注。 |
|
起止段落下标、文本偏移、批注正文和可选元数据。 |
|
给跨段落文本范围添加批注。 |
|
无。 |
|
检查修订记录。 |
|
|
|
接受或拒绝单条修订。 |
|
|
|
追加脚注。 |
|
无。 |
|
编辑前检查超链接文本和目标。 |
|
|
|
在正文追加超链接。 |
|
|
|
替换已有超链接。 |
相关 API 家族¶
Document 根对象还暴露以下公开 API 家族。完整方法集和示例请进入对应专题页:
分节和页面设置 API:分节段落、页眉页脚分配、物理页眉页脚部件删除和页面设置。
字段、链接和审阅 API:批注、批注回复、已解决状态、脚注、尾注、超链接和修订操作。
TemplatePart:模板校验、schema 扫描、模板上架、自定义 XML 同步和内容控件表单状态。
图片 API:行内/浮动图片列表、提取、替换和删除。
Paragraph 和 Run 与 Table、TableRow 和 TableCell:从
Document返回的段落、run、表格、行和单元格编辑入口。
示例¶
打开模板、填充内容控件并保存:
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;
直接从 Document 填充,并读取失败诊断:
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;
创建新文档、追加表格并设置打开时更新域:
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;