Golang处理Word文档模板实现标签填充|表格插入|图标绘制和插入|删除段落|删除标签

news2024/9/17 8:54:00

本教程主要实现【Golang处理Word文档模板实现标签填充|表格插入|图标绘制和插入|删除段落|删除标签】。
本文源码:https://gitee.com/songfayuan/go-zero-demo
教程源码分支:master 分支(_examples/word-template/fill-word-template.go)

Golang处理Word文档模板教程

本教程将指导您使用Golang处理Word文档模板,包括自定义标签填充、动态插入表格、绘制图表和插入图表。我们将使用unioffice库和gg库来完成这些任务。

前提条件

在开始之前,请确保您已安装以下库:

  1. unioffice
  2. gg

您可以使用以下命令安装这些库:

go get -u github.com/Esword618/unioffice
go get -u github.com/fogleman/gg

代码结构

我们的代码分为以下几部分:

  1. 打开Word文档
  2. 填充模板中的变量
  3. 在指定标签处插入表格
  4. 创建折线图并保存为图片
  5. 在指定标签处插入图表
  6. 保存更新后的文档

示例代码

以下是完整的示例代码:

package main

import (
	"fmt"
	"log"
	"strings"

	"github.com/Esword618/unioffice/color"
	"github.com/Esword618/unioffice/common"
	"github.com/Esword618/unioffice/document"
	"github.com/Esword618/unioffice/measurement"
	"github.com/Esword618/unioffice/schema/soo/wml"
	"github.com/fogleman/gg"
)

//教程:https://blog.csdn.net/u011019141/article/details/140788882

func main() {
	// 定义文档路径和图表文件路径
	docPath := "_examples/word-template/template.docx"
	chartFile := "/Users/songfayuan/Downloads/123456.PNG"
	updatedDocPath := "/Users/songfayuan/Downloads/updated_demo.docx"

	// 打开文档
	doc, err := openDocument(docPath)
	if err != nil {
		log.Fatalf("无法打开文档: %v", err)
	}

	// 填充模板中的变量
	fillTemplate(doc, map[string]string{
		"{{TASK_NAME}}": "任务名称示例",
		"{{DETAILS}}":   "详细信息示例",
	})

	// 在指定标签处插入表格
	if err := insertTableAt(doc, "{{biaoge}}"); err != nil {
		log.Fatalf("插入表格时出错: %v", err)
	}

	// 创建折线图并保存为图片
	if err := createLineChart(chartFile); err != nil {
		log.Fatalf("创建图表时出错: %v", err)
	}

	// 在指定标签处插入图表
	if err := insertImageAt(doc, chartFile, "{{tubiao}}"); err != nil {
		log.Fatalf("插入图表时出错: %v", err)
	}

	// 删除{{a}}到{{b}}之间的段落
	if err := removeParagraphsBetweenTags(doc, "{{a}}", "{{b}}"); err != nil {
		log.Fatalf("删除段落时出错: %v", err)
	}

	// 删除指定标签
	if err := removeParagraphWithTag(doc, "{{shanchu}}"); err != nil {
		log.Fatalf("删除指定标签时出错: %v", err)
	}

	// 保存更新后的Word文档
	if err := doc.SaveToFile(updatedDocPath); err != nil {
		log.Fatalf("无法保存文档: %v", err)
	}
	fmt.Println("文档更新成功")
}

// 打开文档
func openDocument(path string) (*document.Document, error) {
	return document.Open(path) // 使用unioffice库打开指定路径的文档
}

// 填充模板中的变量
func fillTemplate(doc *document.Document, replacements map[string]string) {
	for _, para := range doc.Paragraphs() { // 遍历文档中的每个段落
		for _, run := range para.Runs() { // 遍历段落中的每个运行(文本片段)
			text := run.Text()
			for placeholder, replacement := range replacements { // 遍历需要替换的占位符
				if strings.Contains(text, placeholder) { // 如果文本包含占位符
					text = strings.ReplaceAll(text, placeholder, replacement) // 替换占位符
					run.Clear()                                               // 清除原有内容
					run.AddText(text)                                         // 添加替换后的文本
				}
			}
		}
	}
}

// 在指定标签处插入表格
func insertTableAt(doc *document.Document, tag string) error {
	paras := doc.Paragraphs() // 获取文档中的所有段落
	for _, para := range paras {
		if paraContainsTag(&para, tag) { // 如果段落包含指定标签
			// 创建并配置表格
			table := doc.InsertTableAfter(para)     // 在标签段落之后插入表格
			table.Properties().SetWidthPercent(100) // 设置表格宽度为100%
			borders := table.Properties().Borders()
			borders.SetAll(wml.ST_BorderSingle, color.Black, measurement.Dxa) // 设置所有边框为单线黑色

			for i := 0; i < 3; i++ { // 创建表格行和单元格
				row := table.AddRow()
				for j := 0; j < 3; j++ {
					cell := row.AddCell()
					cellPara := cell.AddParagraph()
					cellRun := cellPara.AddRun()
					cellRun.AddText(fmt.Sprintf("单元格 %d-%d", i+1, j+1))
				}
			}

			// 移除标签段落
			replaceParagraphWithTable(&para, tag) // 替换标签段落为表格
			// 删除段落
			doc.RemoveParagraph(para) // 从文档中删除标签段落
			return nil
		}
	}
	return fmt.Errorf("未找到标签 %s", tag) // 如果未找到标签段落,返回错误
}

// 在指定标签处插入图表
func insertImageAt(doc *document.Document, imagePath string, tag string) error {
	paras := doc.Paragraphs() // 获取文档中的所有段落
	for _, para := range paras {
		if paraContainsTag(&para, tag) { // 如果段落包含指定标签
			img, err := common.ImageFromFile(imagePath) // 从文件中加载图片
			if err != nil {
				return fmt.Errorf("无法从文件中加载图片: %v", err)
			}

			// 创建图片引用
			iref, err := doc.AddImage(img) // 将图片添加到文档中
			if err != nil {
				return fmt.Errorf("无法将图片添加到文档: %v", err)
			}

			// 创建新的段落和运行以插入图表
			newPara := doc.InsertParagraphAfter(para) // 在标签段落之后插入新段落
			run := newPara.AddRun()

			// 插入图片到文档
			imgInl, err := run.AddDrawingInline(iref) // 在运行中添加图片
			if err != nil {
				return fmt.Errorf("插入图片时出错: %v", err)
			}
			imgInl.SetSize(6*measurement.Inch, 4*measurement.Inch) // 设置图片尺寸为6x4英寸

			// 移除标签段落
			replaceParagraphWithTable(&para, tag) // 替换标签段落为图表
			// 删除段落
			doc.RemoveParagraph(para) // 从文档中删除标签段落
			return nil
		}
	}
	return fmt.Errorf("未找到标签 %s", tag) // 如果未找到标签段落,返回错误
}

// 判断段落是否包含指定标签
func paraContainsTag(para *document.Paragraph, tag string) bool {
	for _, run := range para.Runs() { // 遍历段落中的每个运行
		if strings.Contains(run.Text(), tag) { // 如果运行文本包含标签
			return true
		}
	}
	return false
}

// 创建折线图并保存为图片
func createLineChart(filename string) error {
	const (
		width  = 640
		height = 480
	)

	dc := gg.NewContext(width, height)
	dc.SetRGB(1, 1, 1) // 背景色为白色
	dc.Clear()

	dc.SetRGB(0, 0, 1) // 线条颜色为蓝色
	dc.SetLineWidth(2)

	data := []struct {
		x, y float64
	}{
		{1, 5}, {2, 7}, {3, 6}, {4, 8}, {5, 9}, // 折线图数据点
	}

	if len(data) > 0 {
		dc.MoveTo(data[0].x*100, height-data[0].y*40) // 移动到第一个数据点
		for _, pt := range data[1:] {
			dc.LineTo(pt.x*100, height-pt.y*40) // 绘制线条到下一个数据点
		}
		dc.Stroke() // 结束绘制
	}

	return dc.SavePNG(filename) // 保存图像为PNG文件
}

// 移除标签段落
func replaceParagraphWithTable(para *document.Paragraph, tag string) {
	// 找到标签的 Run
	for _, run := range para.Runs() {
		log.Printf("替换标签:tag =  %v", tag)
		if strings.Contains(run.Text(), tag) {
			para.InsertRunAfter(para.AddRun())
			run.Clear()         // 清除原有内容
			para.RemoveRun(run) // 移除运行
			break
		}
	}
}

// 删除两个标签之间的段落
func removeParagraphsBetweenTags(doc *document.Document, startTag, endTag string) error {
	paras := doc.Paragraphs()
	startIndex, endIndex := -1, -1

	// 找到包含startTag和endTag的段落索引
	for i, para := range paras {
		if paraContainsTag(&para, startTag) {
			startIndex = i
		}
		if paraContainsTag(&para, endTag) {
			endIndex = i
			break
		}
	}

	if startIndex == -1 {
		return fmt.Errorf("未找到标签 %s", startTag)
	}
	if endIndex == -1 {
		return fmt.Errorf("未找到标签 %s", endTag)
	}
	if startIndex >= endIndex {
		return fmt.Errorf("标签 %s 和 %s 之间的顺序不正确", startTag, endTag)
	}

	// 删除startTag和endTag之间的段落
	for i := startIndex; i <= endIndex; i++ {
		doc.RemoveParagraph(paras[i])
	}

	return nil
}

// 删除指定标签段落
func removeParagraphWithTag(doc *document.Document, tag string) error {
	paras := doc.Paragraphs()
	for _, para := range paras {
		if paraContainsTag(&para, tag) {
			doc.RemoveParagraph(para)
			return nil
		}
	}
	return fmt.Errorf("未找到标签 %s", tag)
}

解释

  1. 打开文档

    doc, err := openDocument(docPath)
    

    使用unioffice库打开指定路径的Word文档。

  2. 填充模板中的变量

    fillTemplate(doc, map[string]string{
        "{{TASK_NAME}}": "任务名称示例",
        "{{DETAILS}}":   "详细信息示例",
    })
    

    遍历文档中的每个段落和运行(文本片段),如果文本包含占位符,将其替换为实际值。

  3. 在指定标签处插入表格

    if err := insertTableAt(doc, "{{biaoge}}"); err != nil {
        log.Fatalf("插入表格时出错: %v", err)
    }
    

    查找包含指定标签的段落,在该段落之后插入表格并删除标签段落。

  4. 创建折线图并保存为图片

    if err := createLineChart(chartFile); err != nil {
        log.Fatalf("创建图表时出错: %v", err)
    }
    

    使用gg库绘制折线图并保存为PNG文件。

  5. 在指定标签处插入图表

    if err := insertImageAt(doc, chartFile, "{{tubiao}}"); err != nil {
        log.Fatalf("插入图表时出错: %v", err)
    }
    

    查找包含指定标签的段落,在该段落之后插入图表并删除标签段落。

  6. 保存更新后的文档

    if err := doc.SaveToFile(updatedDocPath); err != nil {
        log.Fatalf("无法保存文档: %v", err)
    }
    

    将更新后的文档保存到指定路径。

运行代码

确保您已正确安装所需的库,并将代码中的文件路径替换为您自己的路径。运行代码后,您将得到一个填充了模板变量、插入了表格和图表的更新Word文档。

Word模板

标签填充
张三:{{TASK_NAME}}
李四:{{DETAILS}}

插入表格
表格
{{biaoge}}

插入图表
图表
{{tubiao}}

删除标签之间段落
{{a}}
段落1
段落2
段落3
段落4
{{b}}
段落5
删除指定标签
删除指定标签
{{shanchu}}
其他段落
9282892890

拷贝到Word文档中保存为template.docx,长这样:
在这里插入图片描述

代码处理后的Word内容

在这里插入图片描述

The end …

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1962391.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ZFIU001 批导会计凭证报错,通过监控点和消息类来定位触发的位置

在创建会计凭证的时候&#xff0c;发送错误&#xff0c;通过打消息类和消息号的条件断点/监控点才解决 文章目录 报错消息号&#xff1a;F5846 创建监控点创建条件断点 报错原因非常注意 报错 消息号&#xff1a;F5846 创建监控点 创建条件断点 报错原因 非常注意

Java8新特性之Stream-Map

Map一些新方法的具体使用案例 1、getOrDefault:default V getOrDefault(Object key, V defaultValue) package com.qbb.threadpool;import java.util.HashMap; import java.util.Map;/*** author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)* version 1.0* date…

力扣高频SQL 50题(基础版)第三十四题

文章目录 力扣高频SQL 50题&#xff08;基础版&#xff09;第三十四题1978.上级经理已离职的公司员工题目说明实现过程准备数据实现方式结果截图 力扣高频SQL 50题&#xff08;基础版&#xff09;第三十四题 1978.上级经理已离职的公司员工 题目说明 表: Employees -------…

论文阅读:基于生物神经元的模拟游戏世界感知与学习

论文内容概述 AI要90分钟学会的游戏&#xff0c;人脑细胞竟在5分钟搞定了。Cell在2022年的研究中&#xff0c;使用80万体外神经元细胞(DishBrain)竟然学会玩70年代经典街机游戏Pong&#xff01; 论文链接&#xff1a;In vitro neurons learn and exhibit sentience when emb…

HCIA总结

一、情景再现&#xff1a;ISP网络为学校提供了DNS服务&#xff0c;所以&#xff0c;DNS服务器驻留在ISP网络内&#xff0c;而不再学校网络内。DHCP服务器运行在学校网络的路由器上 小明拿了一台电脑&#xff0c;通过网线&#xff0c;接入到校园网内部。其目的是为了访问谷歌网站…

ctfshow 权限维持 web670--web679

web670 <?php// 题目说明&#xff1a; // 想办法维持权限&#xff0c;确定无误后提交check&#xff0c;通过check后&#xff0c;才会生成flag&#xff0c;此前flag不存在error_reporting(0); highlight_file(__FILE__);$a$_GET[action];switch($a){case cmd:eval($_POST[c…

2024年技校云计算实验室建设及云计算实训平台整体解决方案

随着信息技术的飞速发展&#xff0c;云计算已成为推动数字化转型的关键力量。技校作为培养技能型人才的摇篮&#xff0c;建设云计算实验室并配套完善的实训平台&#xff0c;对于提升学生的专业技能、增强就业竞争力具有重要意义。本文旨在提出2024年技校云计算实验室建设及云计…

列表内容过多卡顿?有索引栏如何实现滚动加载?

&#x1f453;写在前面 很多小伙伴可能在开发业务中会遇到这种问题&#xff0c;数据列表过多&#xff0c;造成dom一次性渲染卡顿&#xff0c;本文主要介绍滚动加载&#xff0c;实现在有索引栏的列表中使用滚动加载的方法。 本文技术栈使用的是vue2vant2&#xff0c;其他框架组…

letcode - string

翻转字符串 344. 反转字符串 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/reverse-string/ class Solution { public:void reverseString(vector<char>& s) {reverse(s.begin(),s.end());//直接上逆置接口} }; 函数签名: void reverseStr…

CVPR 2024 录用数据出炉!这些方向是大趋势!

一年一度的计算机视觉和模式识别会议&#xff08;CVPR&#xff09;一直是 CV 界前沿研究的灯塔。 CVPR 2024 录用结果显示&#xff0c;今年共有 2719 篇论文被接收&#xff0c;录用率 23.6%。 那么大模型时代&#xff0c;今年的研究主题有哪些变化&#xff1f; 最近&#xf…

【Python】 ValueError: too many values to unpack 解决方案

【Python】 ValueError: too many values to unpack 解决方案 在Python编程中&#xff0c;ValueError: too many values to unpack是一个常见的错误&#xff0c;通常出现在使用解包操作时。本文将深入探讨这个错误的原因、解决思路、解决方法&#xff0c;并通过具体案例帮助大…

【Python学习手册(第四版)】学习笔记09.3-Python对象类型-分类、引用VS拷贝VS深拷贝、比较、相等、真假值等详解

个人总结难免疏漏&#xff0c;请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。 这部分稍杂&#xff0c;视需要选择目录读取。 主要讲的是对之前的所有对象类型作复习&#xff0c;以通俗易懂、由浅入深的方式进行介绍&#xff0c;所有对象类型…

『康之泉活水馆』手游:打造夏日梦幻水世界

设计背景 夏日的热浪与城市的喧嚣困扰着忙碌奔波的人群&#xff0c;康之泉活水馆&#xff0c;作为多功能的室内水上乐园&#xff0c;以其独特的魅力&#xff0c;成为夏日避暑的理想之地&#xff0c;让身心得以彻底放松。 设计理念 优联前端以康之泉品牌IP形象“康康”为灵感&a…

[GYCTF2020]FlaskApp (pin码,jinja2绕过注入)

题目就是flask 下面是判断模版注入的方法 a{*comment*}b和{{7*7}}base64编码后解码都报错no&#xff0c;无法判断模版引擎 直接用下jinja2的试一试&#xff0c;把编码后的密文拿去解码&#xff0c;payload&#xff1a; {{"".__class__mro(2)__subclasses__()}} 报…

英文文献翻译方法哪个好?高效率的翻译方法分享

三伏天的酷热也抵挡不住学术人探索知识的脚步&#xff0c;阅读和翻译英文文献几乎已经成为了许多研究者和学者的日常。然而在面对浩如烟海的英文资料时&#xff0c;如何高效准确地进行翻译&#xff0c;成为了亟待解决的问题。 今天我便挖掘到了5款实用的英文文献翻译工具&…

4.1.1、操作系统的概述

操作系统的作用:通过资源管理提高计算机系统的效率;改善人机界面向用户提供友好的工作环境。 操作系统的特征:并发性、共享性、虚拟性、不确定性。 操作系统的功能:进程管理、存储管理、文件管理、设备管理、作业管理。 操作系统的分类:批处理操作系统、分时操作系统(轮流使…

美股:苹果选择谷歌芯片支持人工智能技术

最近的研究报告显示&#xff0c;苹果公司在其新一代人工智能工具和功能套件中选择依赖谷歌设计的芯片&#xff0c;而非市场领导者 Nvidia。这一决定引发了业界的关注&#xff0c;尤其是考虑到Nvidia在人工智能处理器市场的主导地位。 谷歌云的TPU在苹果的AI基础设施中发挥关键作…

计算机再过几年会没落?

大部分人卷的计算机&#xff1a;Java web 实际上的计算机&#xff1a;web&#xff0c;图形学&#xff0c;Linux系统开发&#xff0c;一系列嵌入式开发&#xff0c;数据库&#xff0c;高性能服务器&#xff0c;中间件开发&#xff0c;三维建模&#xff0c;网络安全&#xff0c;…

vue2 封装弹框组件

安装 element-ui npm install element-ui --save ---force main.js 导入 import Vue from vue; import ElementUI from element-ui; import element-ui/lib/theme-chalk/index.css; import App from ./App.vue; Vue.use(ElementUI); new Vue({ el: #app, render: h > h(Ap…

Minio、MySQL、Redis、Milvus 安装

CPU&#xff1a;2核↑&#xff0c;内存&#xff1a;4GB↑ 开发工具&#xff1a;eclipse-jee、MySQL Workbench、MobaXterm、Redis Insight... 操作系统&#xff1a;CentOS Stream 9&#xff08;生产环境&#xff09;、Windos 11 Ubuntu 22.04.3&#xff08;开发环境&#xf…