Skip to content

多文档无损合并 ​

AppendDocument 将 src 的每一个节克隆到 dst,并重映射在同一个 OpenXML 包内会冲突的标识符。结果是一份 ZIP,其中的样式、书签与媒体不会互相覆盖。

AppendDocument ​

签名 ​

go
func (d *Document) AppendDocument(src *Document, opts MergeOptions) error

type MergeOptions struct {
	StylePrefix    string
	BookmarkPrefix string
	SectionBreak   string
}

参数 ​

名称类型说明
src*Document源树。nil 返回 word: nil source document。
StylePrefixstring冲突段落/表格样式 ID 的前缀。默认 src_。
BookmarkPrefixstring冲突 w:bookmarkStart 名的前缀。默认 src_。
SectionBreakstring克隆过来的第一节的分节符。默认 nextPage。

重映射范围 ​

标识符行为
段落 / 表格样式 ID冲突名称加上前缀(Note → src_Note)
书签名冲突名称加前缀;唯一名称保持不变
内部超链接锚点更新为新的书签名
图片 / 媒体清空 RelationID;写出时分配新的 rId 与 word/media/imageN

rId 在写出时分配(word2007Writer.nextRel),合并后的 ZIP 中两份文档不会共用关系 ID。

完整示例 ​

go
package main

import (
	"bytes"
	"image"
	"image/color"
	"image/png"
	"log"

	"github.com/yunkeweb/go-word"
	"github.com/yunkeweb/go-word/style"
)

func main() {
	dst := word.New()
	dst.AddParagraphStyle("Note", style.Paragraph{Spacing: style.Spacing{After: 120}})
	a := dst.AddSection()
	a.AddTitle("Document A", 1)
	a.AddText("Bookmark and image from A.", nil, "Note")
	a.AddBookmark("shared")
	a.AddImageBytes("a.png", swatch(color.RGBA{R: 31, G: 78, B: 121, A: 255}), style.Image{Width: 40, Height: 20})

	src := word.New()
	src.AddParagraphStyle("Note", style.Paragraph{Spacing: style.Spacing{After: 200}})
	b := src.AddSection()
	b.AddTitle("Document B", 1)
	b.AddText("Bookmark, image and formula from B.", nil, "Note")
	b.AddBookmark("shared")
	b.AddImageBytes("b.png", swatch(color.RGBA{R: 237, G: 125, B: 49, A: 255}), style.Image{Width: 40, Height: 20})
	b.AddMath(`\frac{1}{2}`)

	if err := dst.AppendDocument(src, word.MergeOptions{SectionBreak: "nextPage"}); err != nil {
		log.Fatal(err)
	}
	if err := dst.Save("merged.docx"); err != nil {
		log.Fatal(err)
	}
}

func swatch(c color.RGBA) []byte {
	img := image.NewRGBA(image.Rect(0, 0, 40, 20))
	for y := 0; y < 20; y++ {
		for x := 0; x < 40; x++ {
			img.Set(x, y, c)
		}
	}
	var buf bytes.Buffer
	if err := png.Encode(&buf, img); err != nil {
		log.Fatal(err)
	}
	return buf.Bytes()
}

Word 中的效果 ​

两页。第 1 页是藏青色色块 + Document A。第 2 页在下一页分节符之后,显示橙色色块,并含可编辑的 1/2 分数。styles.xml 同时有 Note 与 src_Note(段后间距不同)。书签 shared 与 src_shared 都在。ZIP 中有 word/media/image1.png 与 image2.png,各有独立 rId —— 解压时图片不会互相覆盖。

基于 GNU LGPL v3.0 发布。