Fix unused imports and finalize v1.2.0
This commit is contained in:
parent
44c2eb1439
commit
3d74c78d8b
@ -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`) 解析支持,可提取全文纯文本。
|
||||
|
||||
72
README.md
72
README.md
@ -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
24
docx.go
@ -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
|
||||
}
|
||||
|
||||
18
excel.go
18
excel.go
@ -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
3
go.mod
@ -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
6
go.sum
@ -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
26
pdf.go
@ -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
24
pptx.go
@ -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
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user