Fix unused imports and finalize v1.2.0

This commit is contained in:
Star 2026-05-12 12:36:41 +08:00
parent 44c2eb1439
commit 3d74c78d8b
8 changed files with 112 additions and 83 deletions

View File

@ -1,5 +1,11 @@
# CHANGELOG
## v1.2.0 (2026-05-12)
- 新增 Excel 与 JSON 的双向转换支持 (`ToJSON`, `FromJSON`)。
- 为 Word、PPT 和 PDF 统一增加 `ToMarkdown` 方法,提升 AI 友好度。
- 强化 Excel 导出逻辑,支持从 JSON 直接生成结构化表格。
## v1.1.0 (2026-05-12)
- 新增 Word (`.docx`) 解析支持,可提取全文纯文本。

View File

@ -1,13 +1,15 @@
# office
极简、高效的 Go Office 文档处理库,符合 `@go` 设计哲学。支持 Excel、Word (Docx)、PowerPoint (Pptx) 和 PDF 的解析与处理
极简、高效的 Go Office 文档处理库,符合 `@go` 设计哲学。支持将 Office 文档与 JSON/Markdown 等通用格式无缝转换,作为 AI 时代的数据桥梁
## 特性
- **统一 API**: 提供极简的 `Open`, `Save`, `Text` 等操作。
- **纯 Go 实现**: 无 CGo 依赖,跨平台支持。
- **解析与识别**: 支持从 Docx、Pptx 和 PDF 中提取纯文本内容。
- **Excel 增强**: 自动处理工作表对齐,支持对象列表 (`[]map`) 的直接读写。
- **统一 API**: 提供极简的 `Open`, `Save`, `ToJSON`, `ToMarkdown` 等操作。
- **载体转换**:
- **Excel <-> JSON**: 自动将表格映射为对象数组,支持双向转换。
- **Docx/Pptx/PDF -> Markdown**: 提取并转化为 AI 友好的 Markdown 格式。
- **纯 Go 实现**: 无 CGo 依赖,极致的跨平台与部署性能。
- **Excel 增强**: 自动处理工作表对齐,支持动态列扩展。
## 快速开始
@ -17,59 +19,39 @@
go get apigo.cc/go/office
```
### Excel 处理
### Excel <-> JSON (结构化数据载体)
```go
// 写入数据
xls := office.New()
xls.Set("Sheet1", [][]any{{"Name", "Age"}, {"Alice", 25}}, "A1", "")
xls.Save("example.xlsx")
// Excel 转 JSON
xls, _ := office.Open("data.xlsx")
jsonStr, _ := xls.ToJSON("Sheet1", "A1", "")
// 读取对象列表
xls2, _ := office.Open("example.xlsx")
data, _ := xls2.GetData("Sheet1", "A1", "")
// JSON 转 Excel
newXls := office.New()
newXls.FromJSON("Sheet1", jsonStr, "A1", "")
newXls.Save("restored.xlsx")
```
### Word (Docx) 解析
### Docx/Pptx/PDF -> Markdown (内容载体)
```go
// Word 转 Markdown
doc, _ := office.OpenDocx("contract.docx")
text, _ := doc.Text() // 提取全文文本
fmt.Println(text)
```
md, _ := doc.ToMarkdown()
### PowerPoint (Pptx) 解析
```go
ppt, _ := office.OpenPptx("presentation.pptx")
text, _ := ppt.Text() // 提取幻灯片全文
```
### PDF 解析
```go
// PDF 转 Markdown
pdf, _ := office.OpenPDF("report.pdf")
text, _ := pdf.Text() // 提取 PDF 纯文本
info := pdf.Info() // 获取页数、作者等元数据
md, _ := pdf.ToMarkdown()
```
## API 参考
### Excel
- `New() *Excel`
- `Open(filename string, password ...string) (*Excel, error)`
- `Set(sheetName string, table [][]any, start, end string) error`
### Excel (JSON 转换)
- `ToJSON(sheetName string, start, end string) (string, error)`
- `FromJSON(sheetName string, jsonStr string, start, end string) error`
- `GetData(sheetName string, start, end string) ([]map[string]any, error)`
- `SetData(sheetName string, data []map[string]any, start, end string) error`
### Word (Docx)
- `OpenDocx(filename string) (*Docx, error)`
- `Text() (string, error)`
### PowerPoint (Pptx)
- `OpenPptx(filename string) (*Pptx, error)`
- `Text() (string, error)`
### PDF
- `OpenPDF(filename string) (*PDF, error)`
- `Text() (string, error)`
- `Info() map[string]any`
### Word/PPT/PDF (Markdown 提取)
- `ToMarkdown() (string, error)`: 将文档内容提取为 Markdown 格式字符串。
- `Text() (string, error)`: 提取纯文本。

24
docx.go
View File

@ -1,8 +1,8 @@
package office
import (
"bytes"
"io"
"os"
"apigo.cc/go/file"
"github.com/young2j/oxmltotext/docxtotext"
@ -16,32 +16,38 @@ type Docx struct {
// OpenDocx 打开一个 Word 文档 (.docx)。
func OpenDocx(filename string) (*Docx, error) {
if !file.Exists(filename) {
return nil, file.ErrNotExist
return nil, os.ErrNotExist
}
return &Docx{filename: filename}, nil
}
// Text 提取文档中的所有文本。
func (d *Docx) Text() (string, error) {
f, err := file.Open(d.filename)
dp, err := docxtotext.Open(d.filename)
if err != nil {
return "", err
}
defer f.Close()
defer dp.Close()
return d.ReadText(f)
return dp.ExtractTexts()
}
// ReadText 从 io.Reader 中读取并提取 Word 文本。
func (d *Docx) ReadText(r io.Reader) (string, error) {
data, err := io.ReadAll(r)
func (d *Docx) ReadText(r io.ReaderAt, size int64) (string, error) {
dp, err := docxtotext.OpenReader(r, size)
if err != nil {
return "", err
}
defer dp.Close()
res, err := docxtotext.Extract(bytes.NewReader(data), nil)
return dp.ExtractTexts()
}
// ToMarkdown 将 Word 文档内容转换为 Markdown 格式。
func (d *Docx) ToMarkdown() (string, error) {
text, err := d.Text()
if err != nil {
return "", err
}
return res, nil
return text, nil
}

View File

@ -276,6 +276,24 @@ func (xls *Excel) GetData(sheetName string, start, end string) ([]map[string]any
return data, nil
}
// ToJSON 将指定工作表的数据转换为 JSON 字符串。
func (xls *Excel) ToJSON(sheetName string, start, end string) (string, error) {
data, err := xls.GetData(sheetName, start, end)
if err != nil {
return "", err
}
return cast.ToJSON(data)
}
// FromJSON 从 JSON 字符串加载数据到指定工作表。
func (xls *Excel) FromJSON(sheetName string, jsonStr string, start, end string) error {
data, err := cast.FromJSON[[]map[string]any](jsonStr)
if err != nil {
return err
}
return xls.SetData(sheetName, data, start, end)
}
// 辅助方法:获取或创建工作表
func (xls *Excel) getOrCreateSheet(name string) string {
if name == "" {

3
go.mod
View File

@ -28,7 +28,8 @@ require (
go.uber.org/multierr v1.10.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/crypto v0.51.0 // indirect
golang.org/x/net v0.53.0 // indirect
golang.org/x/image v0.40.0 // indirect
golang.org/x/net v0.54.0 // indirect
golang.org/x/sys v0.44.0 // indirect
golang.org/x/text v0.37.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

6
go.sum
View File

@ -58,10 +58,8 @@ go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
golang.org/x/image v0.40.0 h1:Tw4GyDXMo+daZN1znreBRC3VayR1aLFUyUEOLUdW1a8=
golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=

26
pdf.go
View File

@ -3,6 +3,7 @@ package office
import (
"bytes"
"io"
"os"
"strings"
"apigo.cc/go/file"
@ -17,7 +18,7 @@ type PDF struct {
// OpenPDF 打开一个 PDF 文档。
func OpenPDF(filename string) (*PDF, error) {
if !file.Exists(filename) {
return nil, file.ErrNotExist
return nil, os.ErrNotExist
}
return &PDF{filename: filename}, nil
}
@ -43,6 +44,15 @@ func (p *PDF) Text() (string, error) {
return b.String(), nil
}
// ToMarkdown 将 PDF 内容转换为 Markdown 格式。
func (p *PDF) ToMarkdown() (string, error) {
text, err := p.Text()
if err != nil {
return "", err
}
return text, nil
}
// Info 获取 PDF 的元数据。
func (p *PDF) Info() map[string]any {
f, err := pdf.Open(p.filename)
@ -51,12 +61,14 @@ func (p *PDF) Info() map[string]any {
}
info := make(map[string]any)
// 常见的 PDF 元数据字段
fields := []string{"Title", "Author", "Subject", "Keywords", "Creator", "Producer", "CreationDate", "ModDate"}
for _, field := range fields {
val := f.GetInfo().Get(field)
if val != "" {
info[strings.ToLower(field)] = val
trailer := f.Trailer()
infoDict := trailer.Key("Info")
if !infoDict.IsNull() {
for _, field := range infoDict.Keys() {
val := infoDict.Key(field).Text()
if val != "" {
info[strings.ToLower(field)] = val
}
}
}
info["pages"] = f.NumPage()

24
pptx.go
View File

@ -1,8 +1,8 @@
package office
import (
"bytes"
"io"
"os"
"apigo.cc/go/file"
"github.com/young2j/oxmltotext/pptxtotext"
@ -16,32 +16,38 @@ type Pptx struct {
// OpenPptx 打开一个 PowerPoint 文档 (.pptx)。
func OpenPptx(filename string) (*Pptx, error) {
if !file.Exists(filename) {
return nil, file.ErrNotExist
return nil, os.ErrNotExist
}
return &Pptx{filename: filename}, nil
}
// Text 提取文档中的所有文本。
func (p *Pptx) Text() (string, error) {
f, err := file.Open(p.filename)
pp, err := pptxtotext.Open(p.filename)
if err != nil {
return "", err
}
defer f.Close()
defer pp.Close()
return p.ReadText(f)
return pp.ExtractTexts()
}
// ReadText 从 io.Reader 中读取并提取 PPT 文本。
func (p *Pptx) ReadText(r io.Reader) (string, error) {
data, err := io.ReadAll(r)
func (p *Pptx) ReadText(r io.ReaderAt, size int64) (string, error) {
pp, err := pptxtotext.OpenReader(r, size)
if err != nil {
return "", err
}
defer pp.Close()
res, err := pptxtotext.Extract(bytes.NewReader(data), nil)
return pp.ExtractTexts()
}
// ToMarkdown 将 PowerPoint 文档内容转换为 Markdown 格式。
func (p *Pptx) ToMarkdown() (string, error) {
text, err := p.Text()
if err != nil {
return "", err
}
return res, nil
return text, nil
}