Skip to content

Latest commit

 

History

History
289 lines (256 loc) · 7.49 KB

4.11.md

File metadata and controls

289 lines (256 loc) · 7.49 KB

4.11 Go 处理word文件

在Go语言实际开发中,会遇到读取、写入或编辑docx格式文件等情况,目前使用比较多的第三方库有

源码:

  • github.com/unidoc/unioffice
  • github.com/carmel/gooxml
  • github.com/nguyenthenguyen/docx

unidoc/unioffice 功能比较齐全,但是收费的,这里就不做介绍了。 carmel/gooxml: 这个库为unidoc/unioffice免费版,即1.4.0收费版,在双重许可证下提供的。在AGPLv3的条款下可以免费使用。虽然没有收费版功能多,但涵盖了大部分基本功能。 nguyenthenguyen/docx: 是一个简单的操作docx文件go语言库

carmel/gooxml

取docx文件

示例

package main

import (
	"fmt"
	"github.com/carmel/gooxml/document"
	"log"
	"os"
	"strconv"
)

func main() {
	doc, err := document.Open("demo.docx")
	if err != nil {
		log.Fatalf("error opening document: %s", err)
		return
	}
	//批注
	for _, docfile := range doc.DocBase.ExtraFiles {
		if docfile.ZipPath != "word/comments.xml" { //只处理word/comments.xml
			continue
		}
		file, err := os.Open(docfile.DiskPath)
		if err != nil {
			continue
		}
		defer file.Close()
		f, err := file.Stat()
		if err != nil {
			continue
		}
		size := f.Size()
		var fileinfo []byte = make([]byte, size)
		_, err = file.Read(fileinfo)
		if err != nil {
			continue
		}
		//实际应该解析<w:t>中的数据
		fmt.Println(string(fileinfo))
	}

	//书签
	for _, bookmark := range doc.Bookmarks() {
		bookname := bookmark.Name()
		if len(bookname) == 0 {
			continue
		}
		fmt.Println(bookmark.Name())
	}

	//页眉
	for _, head := range doc.Headers() {
		var text string
		for _, para := range head.Paragraphs() {
			for _, run := range para.Runs() {
				text += run.Text()
			}
		}
		if len(text) == 0 {
			continue
		}
		fmt.Println(text)
	}

	//页脚
	for _, footer := range doc.Footers() {
		for _, para := range footer.Paragraphs() {
			var text string
			for _, run := range para.Runs() {
				text += run.Text()
			}
			if len(text) == 0 {
				continue
			}
			fmt.Println(text)
		}
	}
	//输出图片
	//var fileBytes []byte
	for k, img := range doc.Images {  //返回文档内所有图片
		fmt.Println("image:", k, img.Format(), img.Path(), img.Size())
	}


	//doc.Paragraphs()得到包含文档所有的段落的切片
	for _, para := range doc.Paragraphs() {
		var text string
		//run为每个段落相同格式的文字组成的片段
		for _, run := range para.Runs() {
			text += run.Text()
			//fmt.Println("粗体", run.Properties().IsBold(), run.Text())   //判断是否是粗体
			//fmt.Println("粗体属性值", run.Properties().BoldValue(), run.Text())
			// fmt.Println("斜体", run.Properties().IsItalic(), run.Text()) //判断是否是斜体
			//fmt.Println("斜体属性值", run.Properties().ItalicValue(), run.Text())
		}
		if len(text) == 0 {
			continue
		}
		//打印一段
		fmt.Println(text)
	}

	//获取表格中的文本
	for tId, table := range doc.Tables() {
		for rowId, run := range table.Rows() {
			for cellId, cell := range run.Cells() {
				var text string
				for _, para := range cell.Paragraphs() {
					for _, run := range para.Runs() {
						text += run.Text()
						//fmt.Println("粗体", run.Properties().IsBold(), run.Text())   //判断是否是粗体
						//fmt.Println("粗体属性值", run.Properties().BoldValue(), run.Text())
						// fmt.Println("斜体", run.Properties().IsItalic(), run.Text()) //判断是否是斜体
						//fmt.Println("斜体属性值", run.Properties().ItalicValue(), run.Text())
					}
				}
				if len(text) == 0 {
					continue
				}
				fmt.Println(text)
				fmt.Println("table"+strconv.Itoa(tId), "行"+strconv.Itoa(rowId), "列"+strconv.Itoa(cellId))
			}
		}
	}

}

创建docx文件

示例

package main

import (
	"github.com/carmel/gooxml/color"
	"github.com/carmel/gooxml/common"
	"github.com/carmel/gooxml/document"
	"github.com/carmel/gooxml/measurement"
	"github.com/carmel/gooxml/schema/soo/wml"
	"log"
)

func main() {
	doc := document.New()
	para := doc.AddParagraph() // 新增段落
	run := para.AddRun()
	//设置段落
	para.SetStyle("Title")
	para.SetStyle("Heading1")  // Heading1 Heading2 Heading3
	para.Properties().SetFirstLineIndent(0.5 * measurement.Inch) // 段落添加首行缩进

	// 换行处理,使用'\r'
	run.AddText("这里是段落文字信息\n这里是第二行段落文字信息") // 添加文字信息
	para.Properties().AddSection(wml.ST_SectionMarkNextPage) // 另起一页(用在AddText之后)

	//设置字体样式
	run.Properties().SetBold(true)             // 是否加粗
	run.Properties().SetFontFamily("Courier")  // 字体
	run.Properties().SetSize(15)               // 字号
	run.Properties().SetColor(color.Red)       // 文字颜色
	run.Properties().SetKerning(5)             // 文字字距
	run.Properties().SetCharacterSpacing(5)    // 字符间距调整
	run.Properties().SetHighlight(wml.ST_HighlightColorYellow) // 设置高亮
	run.Properties().SetUnderline(wml.ST_UnderlineWavyDouble, color.Red) // 下划线

	// 初始化图片信息
	img1, err := common.ImageFromFile("demo.jpg")
	if err != nil {
		log.Fatalf("unable to create image: %s", err)
	}
	img1ref, err := doc.AddImage(img1)
	if err != nil {
		log.Fatalf("unable to add image to document: %s", err)
	}
	// 将图片添加到对应的段落
	anchored, err := para.AddRun().AddDrawingAnchored(img1ref)
	if err != nil {
		log.Fatalf("unable to add anchored image: %s", err)
	}
	// 设置图片相关样式
	anchored.SetName("图片名称")
	anchored.SetSize(2*measurement.Inch, 2*measurement.Inch)
	anchored.SetOrigin(wml.WdST_RelFromHPage, wml.WdST_RelFromVTopMargin)
	anchored.SetHAlignment(wml.WdST_AlignHCenter)
	anchored.SetYOffset(3 * measurement.Inch)
	anchored.SetTextWrapSquare(wml.WdST_WrapTextBothSides)
	
	//添加表格
	table := doc.AddTable()
	// width of the page
	table.Properties().SetWidthPercent(100)
	// with thick borers
	borders := table.Properties().Borders()
	borders.SetAll(wml.ST_BorderSingle, color.Auto, measurement.Zero)
	row := table.AddRow()
	row.AddCell().AddParagraph().AddRun().AddText("姓名")
	row = table.AddRow()
	row.AddCell().AddParagraph().AddRun().AddText("hello")

	doc.SaveToFile("document.docx") // 保存文件路径,此处应为绝对路径
}

nguyenthenguyen/docx

读取docx文件

示例:

package main
import (
	"fmt"
	"github.com/nguyenthenguyen/docx"
)
func main() {
	// Read from docx file
	r, err := docx.ReadDocxFile("./demo.docx")
	// Or read from memory
	// r, err := docx.ReadDocxFromMemory(data io.ReaderAt, size int64)

	// Or read from a filesystem object:
	// r, err := docx.ReadDocxFromFS(file string, fs fs.FS)

	if err != nil {
		panic(err)
	}
	docx1 := r.Editable()
	//获取内容
	content:=docx1.GetContent()
	fmt.Println(content)
	r.Close()
}

编辑docx文件

示例:


package main

import (
	"fmt"
	"github.com/nguyenthenguyen/docx"
)

func main() {
	r, err := docx.ReadDocxFile("./demo.docx")
	if err != nil {
		panic(err)
	}
	docx1 := r.Editable()
	//替换内容
	docx1.Replace("旧文字", "新文字", -1)
	docx1.ReplaceLink("http://example.com/", "https://github.com/nguyenthenguyen/docx", 1)
	//替换页头信息
	docx1.ReplaceHeader("head", "页头")
	//替换页尾信息
	docx1.ReplaceFooter("第一页", "new footer")
	//替换图片
	//docx1.ReplaceImage("word/media/image1.png", "./new.png")
	docx1.WriteToFile("./new_demo.docx")
	r.Close()
}

links

https://pkg.go.dev/github.com/nguyenthenguyen/docx#section-readme https://www.cnblogs.com/xingzr/p/17370295.html

  • 目录
  • 上一节:
  • 下一节: