使用 Go 渲染模板

2024-09-24#Go#模板引擎

模板引擎是软件开发者的常用工具。绝大部分 Web 软件开发者会使用某种引擎渲染 HTML 页面;一些数据工程师也有使用模板引擎的经历,比如知名的数据转换工具 DBT 使用了 Python 编写的 Jinja 模板,用于渲染数据转换的 SQL 代码。简单的模板引擎可能只是变量替换,复杂一些的模板引擎还提供了分支、循环等控制结构,以及模块化的代码组织机制。而在 Web 时代出生的 Go 语言,在标准库内置了就内置了支持文本和HTML渲染的模板库。

Go 语言中的模板引擎 🔗

标准库中的模板引擎 🔗

Go标准库里包括用于渲染文本的 text/template 和渲染HTML的 html/template,支持添加模板中的函数。不过它使用了一种不太常见的语法,初学者可能不太习惯。但是,依然有一些很知名的开源项目在使用它。比如用于生成静态网站的 Hugo,以及 Kubernetes 的包管理工具 Helm。其中,Helm 除了添加自定义的 include required 等函数外,并还使用了第三方 sprig 扩展了模板函数,见其文档 《Know Your Template Functions》。

第三方开源模板引擎 🔗

除标准库之外,开源的模板引擎(或者模板语言)还有:

更多的使用 Go 编写的模板引擎可见 Awesome GoTemplate Engines

text/template 的使用示例 🔗

text/template 的文档详细介绍了模板的使用方法,在不再赘述。这里给出一个真实的例子:假定在一个复杂的项目中,需要渲染多个模板文件,而这些文件又共用了一些片段,如何组织代码呢?这个场景非常类似于 Helm 中的模板:templates/ 里的每个文件是部署到 Kubernetes 中的一种 Kind,共用的片段位于 _helper.tpl 文件中。

代码 🔗

为了便于演示,创建一个极简的示例:

  • 创建templates 文件夹。包括两个文件:main.yamlhelper.tpl
  • Go 代码: main.go

templates/main.yaml 内容如下:

title: {{ template "main.title" }}

templates/helper.tpl 内容如下:

{{ define "main.title" -}}
This is the title
{{- end }}

main.go 内容如下:

package main

import (
	"log"
	"os"
	"text/template"
)

func main() {
	if err := invoke(); err != nil {
		log.Fatalln(err)
	}
}

func invoke() error {
	tmpl, err := template.New("main.yaml").ParseFiles("./templates/main.yaml", "./templates/helpers.tpl")
	// or
	// tmpl, err := template.ParseFiles("./templates/main.yaml", "./templates/helpers.tpl")
	if err != nil {
		return err
	}

	if err := tmpl.Execute(os.Stdout, nil); err != nil {
		return err
	}
	return nil
}

执行 go run main.go 之后,控制台的输出内容为:

title: This is the title

代码解释 🔗

  • Go 代码中的template.ParseFiles 函数创建了一个新的模板,其参数为文件路径,它会解析这些文件里的模板函数。最终渲染的文件是该函数的第一个参数。
  • helpers.tpl 里的 define 是一个 Action,用于定义一个模板(另一个定义模板的 Action是 block,它是 define 的快捷方式);在其他模板中,可使用 template 和模板名称执行这个模板。

加载中...