JSON Schema
概述
gpdf 支持完全使用 JSON 定义文档。这适用于:
- API 驱动的 PDF 生成
- 从外部数据生成动态文档
- 无需 Go 代码的模板系统
- 基于配置的文档创建
基本用法
schema := []byte(`{
"page": {"size": "A4", "margins": "20mm"},
"body": [
{"row": {"cols": [
{"span": 12, "text": "Hello from JSON!", "style": {"size": 24, "bold": true}}
]}}
]
}`)
doc, err := template.FromJSON(schema, nil)
if err != nil {
log.Fatal(err)
}
data, err := doc.Generate()
┌─ A4 ──────────────────────────────────┐
│ │
│ Hello from JSON! ← 24pt, Bold │
│ │
└───────────────────────────────────────┘
使用 Go 模板进行数据绑定
JSON schema 支持 Go 模板表达式以生成动态内容:
schema := []byte(`{
"page": {"size": "A4", "margins": "20mm"},
"metadata": {"title": "{{.Title}}"},
"body": [
{"row": {"cols": [
{"span": 12, "text": "{{.Title}}", "style": {"size": 24, "bold": true}}
]}},
{"row": {"cols": [
{"span": 12, "text": "Author: {{.Author}}"}
]}}
]
}`)
data := map[string]any{
"Title": "Quarterly Report",
"Author": "ACME Corporation",
}
doc, err := template.FromJSON(schema, data)
Schema 结构
{
"page": {
"size": "A4",
"margins": "20mm"
},
"metadata": {
"title": "Document Title",
"author": "Author Name",
"subject": "Subject",
"creator": "Creator"
},
"header": [ /* rows */ ],
"footer": [ /* rows */ ],
"body": [ /* rows */ ]
}
页面配置
| 字段 | 值 | 默认值 |
|---|---|---|
size | "A4", "A3", "Letter", "Legal" | "A4" |
margins | 尺寸字符串:"20mm", "1in", "15pt" | — |
行和列
{"row": {"cols": [
{"span": 6, "text": "Left column"},
{"span": 6, "text": "Right column"}
]}}
完整示例
schema := []byte(`{
"page": {"size": "A4", "margins": "20mm"},
"metadata": {"title": "JSON Schema Example", "author": "gpdf"},
"header": [
{"row": {"cols": [
{"span": 6, "text": "gpdf JSON Schema", "style": {"size": 16, "bold": true, "color": "#1A237E"}},
{"span": 6, "text": "Document Header", "style": {"align": "right", "italic": true}}
]}},
{"row": {"cols": [
{"span": 12, "line": {"color": "#1A237E", "thickness": "1pt"}}
]}}
],
"footer": [
{"row": {"cols": [
{"span": 12, "elements": [
{"type": "line"},
{"type": "pageNumber", "style": {"align": "center"}}
]}
]}}
],
"body": [
{"row": {"cols": [
{"span": 12, "text": "JSON Schema Generation", "style": {"size": 24, "bold": true}}
]}},
{"row": {"cols": [
{"span": 12, "spacer": "5mm"}
]}},
{"row": {"cols": [
{"span": 12, "text": "This PDF was generated from a JSON schema. No Go builder code needed!"}
]}},
{"row": {"cols": [
{"span": 12, "spacer": "10mm"}
]}},
{"row": {"cols": [
{"span": 6, "elements": [
{"type": "text", "content": "Features", "style": {"size": 16, "bold": true}},
{"type": "list", "list": {"items": [
"Declarative document definition",
"All element types supported",
"Style options",
"Header and footer support"
]}}
]},
{"span": 6, "elements": [
{"type": "text", "content": "Supported Elements", "style": {"size": 16, "bold": true}},
{"type": "list", "list": {"type": "ordered", "items": [
"Text with styles",
"Tables with headers",
"Lists (ordered/unordered)",
"Lines and spacers",
"QR codes and barcodes",
"Images (base64)"
]}}
]}
]}},
{"row": {"cols": [
{"span": 12, "spacer": "10mm"}
]}},
{"row": {"cols": [
{"span": 12, "table": {
"header": ["Feature", "Format", "Status"],
"rows": [
["Text styling", "JSON style object", "Supported"],
["Tables", "header + rows arrays", "Supported"],
["Lists", "ordered/unordered", "Supported"],
["Images", "base64 encoded", "Supported"],
["QR codes", "data string", "Supported"],
["Barcodes", "Code128", "Supported"]
],
"columnWidths": [35, 35, 30],
"headerStyle": {"bold": true, "color": "white", "background": "#1A237E"},
"stripeColor": "#F5F5F5"
}}
]}},
{"row": {"cols": [
{"span": 12, "spacer": "10mm"}
]}},
{"row": {"cols": [
{"span": 6, "qrcode": {"data": "https://gpdf.dev", "size": "25mm"}},
{"span": 6, "barcode": {"data": "GPDF-JSON-001", "format": "code128"}}
]}}
]
}`)
doc, err := template.FromJSON(schema, nil)
┌─ A4 ──────────────────────────────────────────────┐
│ gpdf JSON Schema Document Header │ ← header
│ ──────────────────────────────────────────────── │
│ │
│ JSON Schema Generation ← 24pt bold │
│ │
│ This PDF was generated from a JSON schema. │
│ │
│ Features Supported Elements │
│ • Declarative... 1. Text with styles │
│ • All element... 2. Tables with headers │
│ • Style options 3. Lists │
│ • Header/footer 4. Lines and spacers │
│ 5. QR codes and barcodes │
│ 6. Images (base64) │
│ │
│ ┌──────────┬──────────────────┬──────────┐ │
│ │ Feature │ Format │ Status │ │
│ ├──────────┼──────────────────┼──────────┤ │
│ │ Text │ JSON style obj │Supported │ │
│ │ Tables │ header + rows │Supported │ │
│ │ ... │ ... │ ... │ │
│ └──────────┴──────────────────┴──────────┘ │
│ │
│ ┌────┐ ║║│║║│║║║│║║│ │
│ │ QR │ GPDF-JSON-001 │
│ └────┘ │
│ │
│ ──────────────────────────────────────────────── │
│ Page 1 │ ← footer
└───────────────────────────────────────────────────┘
JSON 中的元素类型
列简写
对于单个元素,可以直接在列上使用简写:
{"span": 12, "text": "Hello", "style": {"bold": true}}
{"span": 12, "spacer": "10mm"}
{"span": 12, "line": {"color": "#FF0000"}}
元素数组
要在一列中放置多个元素,使用 elements 数组:
{"span": 12, "elements": [
{"type": "text", "content": "Title", "style": {"size": 18, "bold": true}},
{"type": "spacer", "height": "5mm"},
{"type": "text", "content": "Body text"},
{"type": "line"},
{"type": "pageNumber", "style": {"align": "center"}}
]}
样式对象
{
"size": 16,
"bold": true,
"italic": true,
"color": "#1A237E",
"background": "#F5F5F5",
"align": "center",
"font": "NotoSansJP"
}
| 字段 | 类型 | 说明 |
|---|---|---|
size | number | 字号(单位:点) |
bold | boolean | 粗体 |
italic | boolean | 斜体 |
color | string | 文本颜色("#RRGGBB"、"red"、"blue" 等) |
background | string | 背景颜色 |
align | string | "left"、"center"、"right" |
font | string | 字体族名称 |
表格对象
{
"header": ["Col A", "Col B", "Col C"],
"rows": [
["A1", "B1", "C1"],
["A2", "B2", "C2"]
],
"columnWidths": [40, 30, 30],
"headerStyle": {"bold": true, "color": "white", "background": "#1A237E"},
"stripeColor": "#F5F5F5"
}
列表对象
{"type": "list", "list": {"items": ["Item 1", "Item 2", "Item 3"]}}
{"type": "list", "list": {"type": "ordered", "items": ["First", "Second", "Third"]}}
二维码对象
{"span": 6, "qrcode": {"data": "https://gpdf.dev", "size": "25mm"}}
条形码对象
{"span": 6, "barcode": {"data": "INV-001", "format": "code128"}}
绝对定位
将元素放置在精确的 XY 坐标处,脱离常规网格流:
{
"absolute": [
{
"x": "120mm",
"y": "20mm",
"elements": [
{"type": "text", "content": "CONFIDENTIAL", "style": {"size": 20, "bold": true, "color": "red"}}
]
},
{
"x": "10mm",
"y": "250mm",
"width": "25mm",
"height": "25mm",
"elements": [
{"type": "qrcode", "qrcode": {"data": "https://gpdf.dev", "size": "20mm"}}
]
},
{
"x": "0mm",
"y": "0mm",
"origin": "page",
"elements": [
{"type": "text", "content": "Page origin"}
]
}
]
}
absolute 数组可以出现在顶层(应用到所有页面)或单独的页面定义中。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
x | string | 是 | X 坐标(尺寸字符串) |
y | string | 是 | Y 坐标(尺寸字符串) |
width | string | 否 | 显式宽度(默认:剩余空间) |
height | string | 否 | 显式高度(默认:剩余空间) |
origin | string | 否 | "content"(默认)或 "page" |
elements | array | 是 | 元素对象数组 |
尺寸字符串
| 格式 | 示例 |
|---|---|
| 毫米 | "20mm" |
| 点 | "12pt" |
| 厘米 | "2.5cm" |
| 英寸 | "1in" |
命名颜色
JSON schema 支持命名颜色:"red"、"green"、"blue"、"yellow"、"cyan"、"magenta"、"black"、"white"、"gray"。
也可以使用十六进制格式:"#FF6B6B"、"#1A237E"。
结合 Go 选项
使用 Go 选项覆盖或扩展 JSON schema:
fontData, _ := os.ReadFile("fonts/NotoSansJP-Regular.ttf")
doc, err := template.FromJSON(schema, data,
template.WithFont("NotoSansJP", fontData),
template.WithDefaultFont("NotoSansJP", 12),
)