text/template 包基本用法
text/template 包实现了数据驱动的文本模板生成。
基本模板
package main
import (
"bytes"
"fmt"
"text/template"
)
func main() {
// 定义模板
tmpl := `Hello, {{.Name}}! You are {{.Age}} years old.`
// 解析模板
t := template.Must(template.New("greeting").Parse(tmpl))
// 准备数据
data := struct {
Name string
Age int
}{
Name: "张三",
Age: 25,
}
// 执行模板
var buf bytes.Buffer
if err := t.Execute(&buf, data); err != nil {
panic(err)
}
fmt.Println(buf.String())
}
条件判断
package main
import (
"bytes"
"fmt"
"text/template"
)
func main() {
tmpl := `
{{if .IsAdmin}}
欢迎管理员 {{.Name}}!
{{else}}
欢迎用户 {{.Name}}!
{{end}}
`
t := template.Must(template.New("conditional").Parse(tmpl))
admin := struct {
Name string
IsAdmin bool
}{"张三", true}
user := struct {
Name string
IsAdmin bool
}{"李四", false}
var buf bytes.Buffer
t.Execute(&buf, admin)
fmt.Println(buf.String())
buf.Reset()
t.Execute(&buf, user)
fmt.Println(buf.String())
}
循环
package main
import (
"bytes"
"fmt"
"text/template"
)
func main() {
tmpl := `购物清单:
{{range .Items}}- {{.Name}}: ¥{{.Price}}
{{end}}
总计: ¥{{.Total}}
`
type Item struct {
Name string
Price float64
}
data := struct {
Items []Item
Total float64
}{
Items: []Item{
{"苹果", 5.5},
{"香蕉", 3.0},
{"橙子", 4.5},
},
Total: 13.0,
}
t := template.Must(template.New("list").Parse(tmpl))
var buf bytes.Buffer
t.Execute(&buf, data)
fmt.Println(buf.String())
}
使用函数
package main
import (
"bytes"
"fmt"
"strings"
"text/template"
)
func main() {
// 定义自定义函数
funcMap := template.FuncMap{
"upper": strings.ToUpper,
"lower": strings.ToLower,
"add": func(a, b int) int {
return a + b
},
}
tmpl := `
大写: {{.Name | upper}}
小写: {{.Name | lower}}
求和: {{add .A .B}}
`
t := template.Must(
template.New("funcs").Funcs(funcMap).Parse(tmpl),
)
data := struct {
Name string
A, B int
}{"Hello World", 10, 20}
var buf bytes.Buffer
t.Execute(&buf, data)
fmt.Println(buf.String())
}
嵌套模板
package main
import (
"bytes"
"fmt"
"text/template"
)
func main() {
tmpl := `
{{define "header"}}=== {{.Title}} ==={{end}}
{{define "footer"}}=== 结束 ==={{end}}
{{template "header" .}}
内容: {{.Content}}
{{template "footer"}}
`
t := template.Must(template.New("nested").Parse(tmpl))
data := struct {
Title string
Content string
}{
Title: "标题",
Content: "这是内容",
}
var buf bytes.Buffer
t.Execute(&buf, data)
fmt.Println(buf.String())
}
从文件加载模板
package main
import (
"fmt"
"os"
"text/template"
)
func main() {
// 从文件加载模板
t, err := template.ParseFiles("template.html")
if err != nil {
panic(err)
}
data := struct {
Title string
Items []string
}{
Title: "我的列表",
Items: []string{"项目1", "项目2", "项目3"},
}
// 输出到标准输出
t.Execute(os.Stdout, data)
}
实际应用:生成配置文件
package main
import (
"bytes"
"fmt"
"os"
"text/template"
)
const nginxConf = `
server {
listen {{.Port}};
server_name {{.ServerName}};
location / {
proxy_pass http://{{.BackendHost}}:{{.BackendPort}};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
{{range .StaticPaths}}
location {{.Path}} {
alias {{.Alias}};
expires {{.Expires}};
}
{{end}}
}
`
type StaticPath struct {
Path string
Alias string
Expires string
}
type NginxConfig struct {
Port int
ServerName string
BackendHost string
BackendPort int
StaticPaths []StaticPath
}
func main() {
config := NginxConfig{
Port: 80,
ServerName: "example.com",
BackendHost: "localhost",
BackendPort: 8080,
StaticPaths: []StaticPath{
{"/static/", "/var/www/static", "30d"},
{"/images/", "/var/www/images", "7d"},
},
}
t := template.Must(template.New("nginx").Parse(nginxConf))
var buf bytes.Buffer
if err := t.Execute(&buf, config); err != nil {
panic(err)
}
fmt.Println(buf.String())
}
总结
| 语法 | 说明 |
|---|---|
{{.Field}} |
输出字段值 |
{{if .Cond}}...{{end}} |
条件判断 |
{{range .Slice}}...{{end}} |
循环遍历 |
{{template "name"}} |
调用子模板 |
| `{{. | func}}` |
{{func arg1 arg2}} |
调用自定义函数 |
text/template用于纯文本输出html/template提供了 HTML 转义,防止 XSS 攻击,适合生成 HTML