使用Golang生成Docx模板文档的方法与实践

使用Golang生成Docx模板文档的方法与实践 你好,

我是 Go 语言的新手,最近刚开始学习。我想知道是否有任何库或项目可以帮助在 Go 中进行模板化。我的场景是,我拥有一些包含 Jinja2 类型语法的 docx 模板。我有一个 REST API,它接收 JSON 作为输入,并将其传递给模板引擎,以便使用 docx 模板生成 docx 文档。

我想知道是否可以使用 docx 模板来实现。我看到了很多关于 Go 模板特性的示例,它们使用的是 HTML 模板,但我不确定在 docx 模板上是否也能类似地工作。

请问有人能指导我或就此提供建议吗?

3 回复

更多关于使用Golang生成Docx模板文档的方法与实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


有一个适用于简单场景的库:GitHub - lukasjarosch/go-docx: 快速可靠地替换 docx 文档中的占位符。

但由于 docx 是一种极其复杂的格式,存在许多特殊情况,据我所知,目前 Go 语言中还没有一个一体化的、功能完整的模板引擎。

在这些情况下,如果其他语言中存在优秀的解决方案,最好的方式可能是直接从你的 Go 代码中调用某些命令行工具或 C 库。

在Go中处理Docx模板,推荐使用unidoc/unioffice库。它支持在Docx文档中进行模板替换,类似于Jinja2的语法风格。

以下是一个基本示例:

package main

import (
    "bytes"
    "encoding/json"
    "log"
    "github.com/unidoc/unioffice/document"
)

func main() {
    // 1. 加载Docx模板
    doc, err := document.Open("template.docx")
    if err != nil {
        log.Fatal(err)
    }
    defer doc.Close()

    // 2. 准备JSON数据
    jsonData := `{"name":"张三","company":"ABC公司","date":"2023-10-01"}`
    var data map[string]interface{}
    json.Unmarshal([]byte(jsonData), &data)

    // 3. 替换模板变量
    // 模板中应包含如{{.name}}、{{.company}}等占位符
    for _, para := range doc.Paragraphs() {
        for _, run := range para.Runs() {
            text := run.Text()
            // 简单的文本替换逻辑
            for key, value := range data {
                placeholder := "{{." + key + "}}"
                if strVal, ok := value.(string); ok {
                    text = bytes.ReplaceAll([]byte(text), []byte(placeholder), []byte(strVal))
                }
            }
            run.SetText(string(text))
        }
    }

    // 4. 保存生成的文档
    err = doc.SaveToFile("output.docx")
    if err != nil {
        log.Fatal(err)
    }
}

对于更复杂的模板需求(如循环、条件判断),可以结合Go标准库的text/template

package main

import (
    "bytes"
    "text/template"
    "github.com/unidoc/unioffice/document"
)

func processDocxTemplate(templatePath string, data interface{}) error {
    doc, err := document.Open(templatePath)
    if err != nil {
        return err
    }
    defer doc.Close()

    // 提取文档中的所有文本
    var fullText bytes.Buffer
    for _, para := range doc.Paragraphs() {
        for _, run := range para.Runs() {
            fullText.WriteString(run.Text())
        }
    }

    // 使用Go模板引擎处理
    tmpl, err := template.New("docx").Parse(fullText.String())
    if err != nil {
        return err
    }

    var processedText bytes.Buffer
    err = tmpl.Execute(&processedText, data)
    if err != nil {
        return err
    }

    // 将处理后的文本写回文档(实际实现需要更精细的段落和run处理)
    // ... 具体的文本替换逻辑

    return doc.SaveToFile("output.docx")
}

对于表格中的循环替换,可以使用以下方法:

func replaceTableRows(doc *document.Document, data []map[string]string) {
    for _, tbl := range doc.Tables() {
        for rowIdx, row := range tbl.Rows() {
            for cellIdx, cell := range row.Cells() {
                for _, para := range cell.Paragraphs() {
                    for _, run := range para.Runs() {
                        text := run.Text()
                        // 根据行索引获取对应的数据
                        if rowIdx > 0 && rowIdx <= len(data) {
                            rowData := data[rowIdx-1]
                            for key, value := range rowData {
                                placeholder := "{{." + key + "}}"
                                text = bytes.ReplaceAll([]byte(text), 
                                    []byte(placeholder), []byte(value))
                            }
                            run.SetText(string(text))
                        }
                    }
                }
            }
        }
    }
}

安装依赖:

go get github.com/unidoc/unioffice

注意事项:

  1. Docx文件本质上是ZIP格式的XML文档,模板变量需要直接嵌入在文档文本中
  2. 复杂的格式(如表格、样式)在替换时需要保持XML结构完整
  3. 对于大量数据替换,建议使用流式处理以避免内存问题

替代方案:

  • nguyenthenguyen/docx:更轻量的Docx处理库
  • 自行解析Docx的XML:对于简单需求可以直接操作document.xml

这个方案可以直接集成到REST API中,接收JSON输入并返回生成的Docx文档。

回到顶部