跳到主要内容
Office Open

DOCX

补丁

通过替换占位符、字面文本或元数据修改现有 .docx 文件

通过三种方式修补现有 .docx 模板:替换 {{占位符}} 标记、查找并替换字面文本,或覆盖文档元数据。补丁内容可以是内联 run、块级元素(段落、表格)、图片和超链接。

#patchDocument

替换现有 .docx 文件中的占位符:

ts
import { patchDocument } from "@office-open/docx";
import { readFileSync, writeFileSync } from "node:fs";

const result = await patchDocument({
  outputType: "nodebuffer",
  data: readFileSync("template.docx"),
  placeholders: {
    name: {
      type: "paragraph",
      children: [{ text: "张三" }],
    },
  },
});

writeFileSync("output.docx", result);

#补丁类型

每个补丁通过裸字符串字面量 type 区分:

类型说明
"paragraph"用内联运行级内容替换占位符
"document"用块级内容替换占位符

#"paragraph"

将段落中的占位符文本替换为新的 run。默认保留原 run 的格式属性(字体、大小、颜色、加粗等)。

json
{
  "placeholders": {
    "title": {
      "type": "paragraph",
      "children": [
        {
          "text": "你好 ",
          "bold": true
        },
        {
          "text": "世界"
        }
      ]
    }
  }
}

#"document"

用块级元素(段落、表格等)替换占位符。保留周围的上下文。

ts
placeholders: {
  content: {
    type: "document",
    children: [
      { paragraph: { children: ["第一段"] } },
      { paragraph: { children: ["第二段"] } },
      {
        table: {
          rows: [
            {
              cells: [
                { children: [{ paragraph: { children: ["单元格"] } }] },
              ],
            },
          ],
        },
      },
    ],
  },
}

#图片

用图片替换占位符:

ts
placeholders: {
  logo: {
    type: "paragraph",
    children: [
      {
        picture: {
          data: readFileSync("logo.png"),
          transformation: { width: "5.3cm", height: "2.6cm" },
          type: "png",
        },
      },
    ],
  },
}

#超链接

在补丁内容中包含超链接:

json
{
  "placeholders": {
    "website": {
      "type": "paragraph",
      "children": [
        {
          "text": "访问 "
        },
        {
          "hyperlink": {
            "children": [
              {
                "text": "我们的网站"
              }
            ],
            "url": "https://example.com"
          }
        }
      ]
    }
  }
}

#查找与替换

替换字面文本,无需分隔符 — 键按字面值匹配。适用于品牌更换或固定措辞更新。值使用相同的 Patch 结构(段落 run 或块内容):

ts
const result = await patchDocument({
  outputType: "nodebuffer",
  data: templateBuffer,
  findReplace: {
    "Acme Corp": { type: "paragraph", children: [{ text: "Globex", bold: true }] },
    Draft: { type: "paragraph", children: [{ text: "Final" }] },
  },
});

#核心属性

覆盖文档元数据(docProps/core.xml)。值会与现有核心属性合并 — 只需提供要修改的字段:

ts
const result = await patchDocument({
  outputType: "nodebuffer",
  data: templateBuffer,
  coreProperties: { title: "季度报告", creator: "张三" },
});

#追加内容

向文档主体追加块级内容,插入在最后的分节符(<w:sectPr>)之前。它复用与 "document" 补丁相同的 SectionChild 词汇,因此段落、表格、图片和超链接都受支持:

ts
const result = await patchDocument({
  outputType: "nodebuffer",
  data: templateBuffer,
  append: [
    { paragraph: { children: ["追加的段落"] } },
    { paragraph: { children: [{ text: "加粗结尾", bold: true }] } },
  ],
});

追加内容经与 generateDocument 相同的编译路径序列化器处理,其图片和超链接会自动接入文档的关系。追加内容引用的样式和编号必须已存在于模板中。

#节编辑

直接编辑节列表 — 替换整节内容或追加新节。每条替换项用 0-based index 指明目标节(0 = 从文档开头算起):

ts
const result = await patchDocument({
  outputType: "nodebuffer",
  data: templateBuffer,
  sections: {
    replace: [
      {
        index: 0,
        section: {
          children: [{ paragraph: { heading: "Heading1", children: ["第一章 — 已替换"] } }],
        },
      },
    ],
    append: [
      {
        children: [{ paragraph: { children: ["附录"] } }],
        properties: { pageSize: { width: 16838, height: 11906 } },
      },
    ],
  },
});
  • 未给 properties 时,被替换的节保留其现有页面设置;给了 properties 则由新设置接管。
  • 追加的节插入在最后 body 级 sectPr 之前,每节以自己的分节符收尾。未给 properties 的节继承最后一节的页面设置。
  • 子内容与 append 走同一序列化管线(段落、表格、图片、超链接)。
  • 修补进来的节不支持 headers/footers — 它们需要新建 part;请改用 generateDocument。

#批注

向现有文档注入批注,与现有 word/comments.xml 合并。批注 id 从现有最大 id 续编(无则从 0 开始)。两种锚点:

  • paragraphs — 将批注包裹在第 N 个主体段落(0-based,按文档顺序)周围。
  • placeholders — 将批注包裹在含 {{key}} 标记的 run 周围,在占位符替换之前应用。

每条批注复用 CommentOptions 词汇(见批注与修订),但省略 id — 补丁会自动分配续编 id。

ts
const result = await patchDocument({
  outputType: "nodebuffer",
  data: templateBuffer,
  comments: {
    paragraphs: [
      {
        index: 0,
        comments: [{ author: "Alice", children: ["审阅开篇段落。"] }],
      },
    ],
    placeholders: {
      name: [{ author: "Bob", children: ["核对此值。"] }],
    },
  },
});

现有批注会保留 — 新条目追加到 word/comments.xml 并重新序列化,当该 part 为新建时才添加批注关系与 content-type 接线。

#自定义分隔符

默认分隔符为 {{ 和 }}。使用 placeholderDelimiters 自定义:

ts
await patchDocument({
  outputType: "nodebuffer",
  data: templateBuffer,
  placeholders: { name: { type: "paragraph", children: [{ text: "John" }] } },
  placeholderDelimiters: { start: "<<", end: ">>" },
});

#选项

选项类型默认值说明
outputTypestring—输出格式(见导出页面)
dataBuffer | Uint8Array | ...—输入 .docx 文件数据
placeholdersRecord<string, Patch>—分隔符包裹的占位符名称 → 补丁内容
findReplaceRecord<string, Patch>—字面查找字符串 → 补丁内容(无分隔符)
corePropertiesPartial<CorePropertiesOptions>—核心元数据覆盖,与现有值合并
appendSectionChild[]—追加在最后分节符前的块级内容
sections{ replace?, append? }—节编辑:replace 是 { index, section } 数组
comments{ paragraphs?, placeholders? }—向段落或占位符 run 注入批注(与现有合并)
keepOriginalStylesbooleantrue保留原始 run 格式属性
placeholderDelimiters{ start: string, end: string}{ start: "{{", end: "}}" }自定义占位符分隔符

#patchDetector

在修补之前扫描模板以发现所有占位符键:

ts
import { patchDetector } from "@office-open/docx";

const placeholders = await patchDetector({
  data: readFileSync("template.docx"),
});
// ["name", "title", "content", ...]

#提示

  • Word 中跨分割运行的占位符会被库自动处理。
  • 每个占位符的所有出现都会被替换,而非仅第一处 — 正文、页眉、页脚一视同仁。
  • placeholders 和 findReplace 共享同一引擎;可在一次调用中同时使用。
  • 使用 keepOriginalStyles: true(默认)可在替换文本时继承模板的 run 格式(字体、大小、颜色等)。
  • 补丁内容中的图片和超链接会自动添加到文档的关系中。