Word 文档处理工作流¶
本页是 FeatherDoc 处理 Microsoft Word .docx 文件的任务型入口。已经知道要
完成“生成、填充、检查或批量改写文档”时,先从这里选工作流,再进入具体 API
页面查看完整签名和返回语义。
工作流地图¶
任务 |
推荐入口 |
详细说明 |
|---|---|---|
打开、创建和保存文档 |
|
|
填充 Word 模板 |
|
|
编辑正文文本 |
|
|
编辑表格 |
|
|
添加图片 |
|
|
管理分节、页眉和页脚 |
|
|
管理字段、超链接、批注和修订 |
文档级或部件级字段与审阅 API |
|
自动化批量编辑 |
|
打开与保存¶
最小安全流程是打开文档、修改内容、另存为新路径。返回 std::error_code 的
操作失败时,用 last_error() 查看包内条目和详细原因。
#include <featherdoc.hpp>
int main() {
featherdoc::Document doc{"template.docx"};
if (auto error = doc.open()) {
return 1;
}
const auto replaced =
doc.replace_content_control_text_by_tag("customer", "Ada Lovelace");
if (replaced == 0) {
return 1;
}
return doc.save_as("filled.docx") ? 1 : 0;
}
open() 默认执行严格 OPC 结构校验。公开 archive_limits 保持原有 5 个字段,
默认值为 10,000 个条目、单个 XML 部件 64 MiB、单个二进制部件 256 MiB、总解压量
512 MiB、最大压缩比 200。中央目录 64 MiB、单个物理 entry name 511 bytes、全部
entry name 合计 8 MiB 是内部固定 metadata 限制,不是调用方可配置的
archive_limits 字段;entry name 包含嵌入 NUL 时会被拒绝。只有在修复已知损坏
的历史文档时,才显式使用
document_open_options 的 tolerant 模式。调用 set_path()、再次
open() 或 create_empty() 后,必须重新获取段落、Run、表格和模板部件句柄。
懒加载、Custom XML 同步、图片提取和保存都会复验当前完整源包,因此在 open()
后替换文件也不能绕过资源限制或 UTF-8/规范路径检查。它们还会把 entry 名、逻辑身份、
CRC32、大小和目录标记组成的有序 metadata 指纹与 open() 快照比较;不一致时返回
source_archive_changed,而不是混用两代包内容。覆盖源路径的 save() 会在替换前
做最后一次比较,并用打开时的原始限制校验输出。该机制是协作式一致性检测,不是密码学
哈希或跨进程文件锁。
strict 模式要求 ZIP entry 使用 ASCII 规范物理名称和大写 %HH 转义;tolerant
模式可以读取历史包中的 raw Unicode 物理名称,但仍会拒绝存在歧义的逻辑身份。
save()/save_as() 会把复制的 entry 统一写成 percent-encoded 规范名称。
在 tolerant 历史拼写完成规范化后,两种模式都会拒绝逻辑名称中超出 OPC pchar
集合的字符、空段、全点段、以点结尾的段,以及一个 PartName 通过追加路径段即可得到
另一个 PartName 的歧义组合。
[Content_Types].xml 还会按 ASCII 大小写无关身份检查重复的
Override/@PartName 与 Default/@Extension。Unicode 扩展名必须写成 UTF-8
%HH 字节,因为 raw 非 ASCII 文本不符合 ST_Extension。
核心 WordprocessingML 部件允许 transitional namespace 使用默认、别名或合法 UTF-8
前缀,包括中文前缀。FeatherDoc 会把内存 DOM 的元素名和属性名规范化为 w:。
常规保存始终重新序列化主文档及已加载的页眉/页脚;clean 的懒加载 singleton 部件仍可
按原始字节复制,dirty 后保存为规范形式。错误的显式 xmlns:w 绑定会 fail closed。
主文档根错误在 strict 模式被拒绝、在 tolerant 模式记录结构诊断;页眉/页脚根错误在
两种模式下都会使打开失败,懒加载 singleton 根错误则在首次访问时失败。
commentsExtended 不会进入该 WML 规范化器。
每个 Default 和 Override 还必须提供语法合法的 ContentType media
type;缺失属性、非法参数、控制字符、非法 UTF-8 与不支持的非 ASCII token 在两种校验
模式下都会被拒绝。
内部 OPC relationship target 以来源部件为基准,直接按 UTF-8 package path 解析,
不依赖主机文件系统 code page;嵌套页眉、页脚部件及其图片关系同样遵循这一规则。
移动 Document 也会使源对象返回的旧句柄失效;移动赋值还会使目标对象旧状态的
句柄失效。移动后的源对象处于关闭状态,可以重新初始化。移动操作继续保持
noexcept,Document 维持 1.13 对象布局;新增内部 bookkeeping 存放在 opaque
sidecar 中。
修复损坏 DOCX 时,不要把 tolerant 打开成功当成文档已经合法。先读取诊断,再显式 修复并另存;修复成功后也必须重新获取 XML-backed 句柄。
不要因为 tolerant 打开成功就直接进入常规编辑流程;该模式只用于检查和显式修复。
真正缺失的 relationship part 可以由负责它的 API 创建,但已经存在且根节点或 package
namespace、Relationship 子节点 namespace 或结构非法的 document、页眉或页脚
.rels 会受到保护,不会被隐式重建;缺失必需属性、重复 Id 和非法 TargetMode
同样会被拒绝。
超链接、图片、singleton part 和分节 relationship 修改会返回
invalid_package_structure。内容控件图片替换会在修改控件、添加 drawing XML 或媒体
部件、更新 Content Types 之前失败;随后保存仍保留原有非法关系结构,不会静默覆盖。
必须先显式修复诊断指出的包问题,再继续编辑。
合法 relationship 元素按 expanded QName 匹配,因此默认 namespace 与带前缀的
Relationships/Relationship 都受支持。已有前缀会保留,新建 relationship 子节点
复用根节点前缀;OPC relationship 属性本身仍必须不带前缀。
featherdoc::Document damaged{"legacy.docx"};
featherdoc::document_open_options options;
options.validation = featherdoc::package_validation_mode::tolerant;
if (damaged.open(options)) {
return 1;
}
for (const auto &diagnostic : damaged.package_diagnostics()) {
if (!diagnostic.repairable) {
return 1;
}
}
if (!damaged.repair_package()) {
return 1;
}
return damaged.save_as("legacy-repaired.docx") ? 1 : 0;
对应 CLI 流程为 featherdoc_cli inspect-package legacy.docx --json,确认所有问题
可修复后执行 featherdoc_cli repair-package legacy.docx --output
legacy-repaired.docx --json。修复命令强制要求输出路径,不会覆盖输入文件。
模板填充¶
正式业务模板优先使用 Word 书签或内容控件,不要优先依赖全文替换。tag 和 alias 比段落下标更稳定,更适合合同、报价单、发票、通知书这类会反复调整版式的模板。
auto body = doc.body_template();
if (!body) {
return 1;
}
body.replace_bookmark_text("invoice_no", "INV-2026-001");
body.replace_content_control_text_by_tag("customer_name", "Ada Lovelace");
body.replace_content_control_with_table_by_tag("line_items", {
{"Item", "Qty", "Amount"},
{"Support", "1", "100.00"}
});
正文编辑¶
目标是文本内容或 run 级格式时,使用 Paragraph 和 Run。目标是表格结构、
单元格文本、宽度、边框、合并单元格或重复表头时,使用 Table 系列 API。
auto summary = doc.body_template().append_paragraph("Status:");
auto value = summary.add_run(" approved", featherdoc::formatting_flag::bold);
value.set_font_family("Aptos");
summary.set_alignment(featherdoc::paragraph_alignment::center);
auto table = doc.append_table(2, 2);
table.set_row_texts(0, {"Name", "Status"});
table.set_row_texts(1, {"Ada", "Approved"});
页眉、页脚与分节¶
模板存在分节专属页眉或页脚时,先解析目标分节,再用和正文一致的 TemplatePart
操作处理页眉页脚内容。
auto footer = doc.section_footer_template(
0, featherdoc::section_reference_kind::default_reference);
if (footer) {
footer.append_page_number_field();
}
批量编辑¶
scripts/edit_document_from_plan.ps1 是更适合自动化的改写入口。编辑计划使用
UTF-8 JSON,执行时写出 summary,方便 CI 或发布脚本检查每个 operation 的结果。
CLI 在 POSIX 上要求命令行参数是合法 UTF-8;Windows 上直接读取原生 UTF-16 命令行, 中文、日文、emoji、空格和长路径不会经过当前控制台 code page。所有平台上的 JSON、 文本输入、stdout 和 stderr 仍统一使用 UTF-8。
{
"operations": [
{
"op": "replace_content_control_text_by_tag",
"tag": "customer_name",
"text": "Ada Lovelace"
},
{
"op": "append_page_number_field",
"part": "section-footer",
"section": 0
}
]
}
powershell -ExecutionPolicy Bypass -File .\scripts\edit_document_from_plan.ps1 `
-InputDocx .\template.docx `
-EditPlan .\plan.json `
-OutputDocx .\output\filled.docx `
-SummaryJson .\output\filled.summary.json `
-SkipBuild
验证方式¶
建议按层验证:
对改动到的 API 或脚本补 C++ / PowerShell 聚焦测试。
自动化批处理检查
summary_json中的 operation 状态。涉及最终可见版式时,运行
scripts/run_word_visual_smoke.ps1做视觉验证。源文件、JSON 编辑计划和中文文本统一使用 UTF-8。Windows 上排查中文输出时, 用
Get-Content -Encoding UTF8读取文件,并显式设置控制台输出编码。