wordzero

module
v1.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2026 License: MIT

README

修改总览

# 文件 修改内容
1 vendor_wordzero/pkg/document/document.go Run 结构体新增 Pict 字段
2 vendor_wordzero/pkg/document/document.go 新增 VmlPicture 类型(innerxml 捕获 VML)
3 vendor_wordzero/pkg/document/document.go parseRun 新增 pict/br/fldChar/instrText/object 5 个解析分支
4 vendor_wordzero/pkg/document/document.go 新增 parseVmlPicture 函数 + nsPrefix 映射(7 个命名空间)
5 vendor_wordzero/pkg/document/document.go Run.MarshalXML 新增 Pict 序列化
6 vendor_wordzero/pkg/document/document.go serializeDocument 新增 xmlns:v / xmlns:o 命名空间
7 vendor_wordzero/pkg/document/document.go Body.MarshalXML 保留全部 sectPr(原来只保留最后一个)
8 vendor_wordzero/pkg/document/document.go parseSectionProperties 解析 rsidR/rsidRPr/rsidSect + formProt
9 vendor_wordzero/pkg/page.go PageSizeXML.Orient 加 omitempty,避免输出空 w:orient=""
10 vendor_wordzero/pkg/page.go SectionProperties 新增 RSIDR/RSIDRPr/RSIDSect + FormProt
11 vendor_wordzero/pkg/page.go SectionProperties 字段重排,匹配 OOXML schema 子元素顺序
12 vendor_wordzero/pkg/document/document.go Paragraph 新增 BookmarkStarts/BookmarkEnds/Hyperlinks 字段
13 vendor_wordzero/pkg/document/document.go parseParagraph 解析 hyperlink/bookmarkStart/bookmarkEnd + 新增 parseHyperlink
14 vendor_wordzero/pkg/document/toc.go Hyperlink 新增 History 属性
15 vendor_wordzero/pkg/document/document.go parseBodySubElement 新增 sdt 处理 + parseSdtBlock/parseSdtContent 函数
16 vendor_wordzero/pkg/document/document.go 新增 TabChar 类型 + Run 结构体新增 TabChar 字段
17 vendor_wordzero/pkg/document/document.go parseRun 新增 tab 解析分支;Run.MarshalXML 新增 TabChar 序列化
18 vendor_wordzero/pkg/document/document.go parseParagraphProperties 新增 tabs 解析 + 新增 parseTabs 函数
main.go CLI 重构:os.Args 位置参数 → flag 包(-read/-add/-write/-err/-content

Bug 1:图片丢失(共 6 处修复)

现象

读取 docx 后保存,签名图片(VML 格式)丢失。

根因

环节 问题
解析 parseRun 只处理 w:drawing(DrawingML),w:pict(VML)被 default: 跳过
序列化 Run.MarshalXML 只写 w:drawingw:pict 不序列化
命名空间 documentXML 缺少 xmlns:v / xmlns:o,输出文档 VML 无法渲染

修复详情

1. Run 结构体新增 Pict 字段
type Run struct {
    Drawing *DrawingElement `xml:"w:drawing,omitempty"`
    Pict    *VmlPicture     `xml:"w:pict,omitempty"`  // 新增
}
2. 新增 VmlPicture 类型
type VmlPicture struct {
    XMLName  xml.Name `xml:"w:pict"`
    InnerXML string   `xml:",innerxml"`
}
3. parseRun 新增 5 个解析分支
case "pict":       // VML 签名图片
case "br":         // 换行符
case "fldChar":    // 域字符
case "instrText":  // 域指令文本
case "object":     // 跳过嵌入对象
4. 新增 parseVmlPicture 函数 + nsPrefix 映射

Go xml.Decoder 不保留命名空间前缀,按 URI 重建:

urn:schemas-microsoft-com:vml                        → v:
urn:schemas-microsoft-com:office:office              → o:
http://schemas.openxmlformats.org/drawingml/2006/main → a:
5-6. 序列化新增 Pict + VML 命名空间

Run.MarshalXML 增加 Pict 输出;serializeDocument 增加 xmlns:v/xmlns:o 声明。

验证结果

输入: 263 段落, 5747 runs, 77 DrawingML, 3 VML
输出: 263 段落, 5747 runs, 77 DrawingML, 3 VML  ✅

Bug 2:页面设置错误(共 5 处修复)

现象

读取多节 docx 后保存,页边距错误——仅保留最后一节的页面设置,第一节边距丢失。同时出现无效的 w:orient=""

根因

环节 问题
序列化 Body.MarshalXML 只保留最后一个 SectionProperties
PageSizeXML.Orient 缺少 omitempty,空串永远序列化为 w:orient=""
SectionProperties 结构体 缺少 rsidR/rsidRPr/rsidSect + formProt
SectionProperties 字段顺序 子元素顺序不符合 schema(headerReference 须在 pgSz 之前)

修复详情

1. Body.MarshalXML 保留所有 sectPr
// 原: var sectPr *SectionProperties  // 只最后一个
// 改: var sectPrs []*SectionProperties  // 全部
2. PageSizeXML.Orient 加 omitempty
Orient string `xml:"w:orient,attr,omitempty"`  // 加 omitempty
3. SectionProperties 新增属性 + FormProt
RSIDR    string    `xml:"w:rsidR,attr,omitempty"`
RSIDRPr  string    `xml:"w:rsidRPr,attr,omitempty"`
RSIDSect string    `xml:"w:rsidSect,attr,omitempty"`
FormProt *FormProt `xml:"w:formProt,omitempty"`
4-5. parseSectionProperties 解析 + 字段重排

结构体字段顺序按 OOXML schema 排列:headerReference → footerReference → pgSz → pgMar → ...


Bug 3:SDT 包裹的 TOC 目录内容丢失(共 1 处修复)

现象

读取 docx 后保存,目录(TOC)条目、书签全部消失。

根因

Word 生成的 TOC 内容通常包裹在 <w:sdt>(Structured Document Tag)中:

<w:sdt>
  <w:sdtPr>...</w:sdtPr>
  <w:sdtContent>
    <w:p>
      <w:bookmarkStart w:id="0" w:name="_Toc123"/>
      <w:hyperlink w:anchor="_Toc456" w:history="1">
        <w:r>...</w:r>
      </w:hyperlink>
      <w:bookmarkEnd w:id="0"/>
    </w:p>
  </w:sdtContent>
</w:sdt>

parseBodySubElement 不认识 sdt 元素,直接调用 skipElement 跳过了整个 <w:sdt> 及其内部所有内容。这导致:

丢失内容 修复前 修复后
Hyperlinks 0 7
BookmarkStarts 0 34
BookmarkEnds 0 34
Body Elements 263 275

修复详情

parseBodySubElement 新增 sdt 处理 + parseSdtBlock / parseSdtContent
// parseBodySubElement 新增:
case "sdt":
    return d.parseSdtBlock(decoder, startElement)

新增 parseSdtBlockparseSdtContent 两个函数,解包 <w:sdtContent> 内的段落和表格,直接加入 Body.Elements

func (d *Document) parseSdtBlock(...) {
    // 跳过 <w:sdtPr>,进入 <w:sdtContent> 提取子元素
}

func (d *Document) parseSdtContent(...) {
    // 解析内层 <w:p> 和 <w:tbl>,加入 Body.Elements
}

Bug 4:页面全空(共 0 处新增,修正原有修复#12)

现象

保存后 Word 打开文档页面完全空白。

根因

修复 #12 曾为 Paragraph 实现了自定义 MarshalXML,但 Go XML 编码器在通过 interface{}BodyElement)传递 *Paragraph 时,会将 Go 类型名 "Paragraph" 作为 XML 元素名输出,导致生成 <Paragraph> 而非 <w:p>。Word 无法识别 <Paragraph> 标签,页面全空。

尝试通过 EncodeToken(start) 修正命名空间前缀也失败——EncodeToken 生成 <p xmlns="...">,仍然缺少 w: 前缀。

最终方案

放弃自定义 MarshalXML,改用 Go 默认 XML 序列化。Paragraph 结构体通过字段顺序控制子元素输出顺序:

// 最终版本:所有字段使用标准 xml tag,按 OOXML schema 顺序排列
type Paragraph struct {
    XMLName         xml.Name             `xml:"w:p"`
    Properties      *ParagraphProperties `xml:"w:pPr,omitempty"`
    BookmarkStarts  []*BookmarkStart     `xml:"w:bookmarkStart,omitempty"`
    Hyperlinks      []*Hyperlink         `xml:"w:hyperlink,omitempty"`
    Runs            []Run                `xml:"w:r,omitempty"`
    BookmarkEnds    []*BookmarkEnd       `xml:"w:bookmarkEnd,omitempty"`
}

Go XML 编码器直接按 struct 字段顺序输出 <w:p><w:pPr>...</w:pPr><w:bookmarkStart>...</w:bookmarkStart>...,完美匹配 OOXML schema。

教训

在 Go 中通过 interface{} 传递 struct 时,不应依赖自定义 MarshalXML 生成带命名空间的标签,Go 编码器默认只保留 XMLName 标签信息。优先使用 struct tag 驱动默认序列化。


Bug 5:TOC 点线(dot leader)和制表符丢失(共 4 处修复)

现象

保存后,目录(TOC)中标题与页码之间的 ...... 点线消失,页码和标题挤在一起无法对齐。

根因

TOC 点线由两个 XML 元素共同渲染:

元素 位置 作用
<w:tabs> 段落属性 <w:pPr> 定义制表位位置(pos)和点线样式(leader
<w:tab/> run 内 <w:r> 实际制表符,填充 <w:tabs> 定义的 leader

两个元素均被忽略:

环节 问题
parseParagraphProperties 不认识 tabs 元素,走 default: skipElement,制表位定义全丢
Run 结构体 缺少 TabChar 字段,parseRun 不认识 tab,制表符被跳过
Run.MarshalXML 不序列化 TabChar

修复详情

1. 新增 TabChar 类型 + Run 字段
type TabChar struct {
    XMLName xml.Name `xml:"w:tab"`
}

type Run struct {
    // ...
    TabChar *TabChar `xml:"w:tab,omitempty"`  // 新增
}
2. parseRun 新增 tab 解析 + MarshalXML 序列化
// parseRun:
case "tab":
    run.TabChar = &TabChar{}
    if err := d.skipElement(decoder, t.Name.Local); err != nil {
        return nil, err
    }

// Run.MarshalXML:
if r.TabChar != nil {
    if err := e.EncodeElement(r.TabChar, ...); err != nil {
        return err
    }
}
3. parseParagraphProperties 新增 tabs 解析
case "tabs":
    tabs, err := d.parseTabs(decoder)
    // ...
    paragraph.Properties.Tabs = tabs
4. 新增 parseTabs 函数
func (d *Document) parseTabs(decoder *xml.Decoder) (*Tabs, error) {
    // 解析每个 <w:tab> 子元素的 val/leader/pos 属性
    tabs := &Tabs{}
    // ...
    case "tab":
        tab := TabDef{
            Val:    getAttributeValue(t.Attr, "val"),
            Leader: getAttributeValue(t.Attr, "leader"),
            Pos:    getAttributeValue(t.Attr, "pos"),
        }
        tabs.Tabs = append(tabs.Tabs, tab)
}

Directories

Path Synopsis
examples
advanced_features command
Package main 演示WordZero高级功能
Package main 演示WordZero高级功能
alignment_demo command
basic command
Package main 展示WordZero基础功能使用示例
Package main 展示WordZero基础功能使用示例
cell_advanced command
cell_iterator command
enhanced_template_demo command
Package main 演示增强的模板功能
Package main 演示增强的模板功能
formatting command
image_persistence_demo command
Package main 演示图片持久性修复:打开包含图片的文档,修改后重新保存,图片不会丢失
Package main 演示图片持久性修复:打开包含图片的文档,修改后重新保存,图片不会丢失
issue_scenario_test command
Package main 测试与issue描述完全一致的场景
Package main 测试与issue描述完全一致的场景
markdown_demo command
nested_loop_demo command
Package main 演示嵌套循环功能
Package main 演示嵌套循环功能
page_settings command
Package main 页面设置功能示例
Package main 页面设置功能示例
pagination_deletion_demo command
Package main 演示分页和段落删除功能
Package main 演示分页和段落删除功能
style_demo command
Package main 展示WordZero完整样式系统的使用示例
Package main 展示WordZero完整样式系统的使用示例
table command
Package main 演示WordZero表格功能
Package main 演示WordZero表格功能
table_layout command
table_style command
template_demo command
Package main 模板功能演示示例
Package main 模板功能演示示例
template_from_file_demo command
Package main 演示动态创建复杂模板文件并渲染
Package main 演示动态创建复杂模板文件并渲染
template_image_demo command
Package main 图片占位符模板功能演示示例
Package main 图片占位符模板功能演示示例
template_inheritance_demo command
Package main 模板继承功能演示
Package main 模板继承功能演示
toc_update_demo command
Package main 演示UpdateTOC功能
Package main 演示UpdateTOC功能
pkg
document
Package document 提供了用于创建、编辑和操作 Microsoft Word 文档的 Golang 库。
Package document 提供了用于创建、编辑和操作 Microsoft Word 文档的 Golang 库。
markdown
Package markdown 提供Markdown到Word文档的转换功能
Package markdown 提供Markdown到Word文档的转换功能
style
Package style 样式应用API
Package style 样式应用API

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL