网络服务总是以HTML网页或者数据的形式回复客户的请求,这通常都带有很多的内容,这包括用户所请求的数据或者HTML结构,使用模板能让我们更方便的将普通的纯文本内容转换为有着特殊格式的文本,比如下面这种情况:

Template:
+---------------+
| Hello, {NAME} |-----+
+---------------+     |     +-------------+
Data:                 +---> + Hello, Mary |
+---------------+     |     +-------------+
| NAME = "Mary" |-----+
+---------------+

在Go中,我们使用 *templates*包中的如 *Parse*、*ParseFile*、*Execute*等方法从一段字符串或者一个模板文件加载模板然后转换为输出,这些用来添加到模板中的数据一些都保存在某个可以被导入的类型字段中,比如上面这个示例可以是这样的实现:

+--------------------+
|template:           |
|"Hello, {NAME}"     |-----+
+--------------------+      -------+     +-------------+
                 template.Execute() +---> + Hello, Mary |
+--------------------+      /-------+     +-------------+
|type struct:        |-----+
|Person{NAME:"Mary"} |
+--------------------+

最典型的使用方法是为网页生成HTML代码的文件,我们需要选择打开一个已经定义好报模板文件,然后使用*template.Execute*方法将一些数据填充到模板文件中,接着使用 *http.ResponseWriter*将结果发入到返回给客户端的数据流。

func handler(w http.ResponseWriter, r *http.Request) {
    t := template.New("some template") // 创建一个新的 template
    t, _ = t.ParseFiles("tmpl/welcome.html", nil) // 从文本文件打开并分析一个模板
    user := GetCurrentlyLoggedInUser() // 一个用来获取当前登陆用户信息的文法
    t.Execute(w, User)
}
  • 对于你真实的网站开始,你可能需要使用 *template.ParseFiles*,但是在这里,我们做为示例,就不再单独写一个模板文件了,而是直接使用 *template.Parse*,它与前者有一样的功能,只是它不是从一个文件中读取模板,而是直接从一个字符串中创建模板。
  • 我们不将示例写作一个Web服务,而是直接将结果打开到我们的命令行终端中。这便得我们需要使用 *io.Stdout*,它关联到我们的标准输出——os.Stdout实现了io.Writer接口。

字段替换——{{.FieldName}}

要在模板文件中输出字段一数据,只需要在该字段名称前面加一个小数点“.*”,然后再将其放入一个双层的大括号“{{}}”里面即可,比如我们需要输出的字段为 *Name*,那么就只需要把 *{{.Name}} 放在模板文件的合适的位置即可。

package main

import (
    "os"
    "text/template"
)

type Person struct {
    Name string // 可导出的字段
}

func main() {
    t := template.New("Hello Template") // 创建一个名为 Hello Template 的模板
    t, _ = t.Parse("Hello {{.Name}}") // 分析模板并创建一个模板
    p := Person{Name:"Mary"} // 定义一个实例
    t.Execute(os.Stdout, p) // 转换模板t,填充了p中的数据
}

输出为:

Hello Mary

为了完整演示,我在这模板里面添加一个不存在的字段nonExportedAgeField*,它是以小写字母开头的,所以未导出,这会导致一个错误,你可以从 *Execute 方法的返回结果中获取到错误信息。

package main

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

type Person struct {
    Name string
    nonExportedAgeField string
}

func main() {
    p := Person{Name: "Mary", nonExportedAgeField: "44"}
    t := template.New("nonexported template demo")
    t, _ = t.Parse("Hello {{.Name}}! Age is {{.nonExportedAgeField}}.")
    err := t.Execute(os.Stdout, p)
    if err != nil {
        fmt.Println("There was an error:", err)
    }
}

输出为:

Hello Mary! Age is There was an error: template: nonexported template demo:1: can't evaluate field nonExportedAgeField in type main.Person

template.Must函数——检测模板是否正确

template中的静态函数 *Must*可以检测模板是否正确,比如标签是否都已经关闭或者变量是否都是可输出的等等:

package main

import (
    "text/template"
    "fmt"
)

func main() {
    tOk := template.New("first")
    template.Must(tOk.Parse(" some static text /* and a comment */")) //a valid template, so no panic with Must
    fmt.Println("The first one parsed OK.")

    template.Must(template.New("second").Parse("some static text {{ .Name }}"))
    fmt.Println("The second one parsed OK.")

    fmt.Println("The next one ought to fail.")
    tErr := template.New("check parse error with Must")
    template.Must(tErr.Parse(" some static text {{ .Name }")) // due to unmatched brace, there should be a panic here
}

输出为:

The first one parsed OK.
The second one parsed OK.
The next one ought to fail.
panic: template: check parse error with Must:1: unexpected "}" in command

goroutine 1 [running]:
text/template.Must(0x0, 0xf840031030, 0xf840034380, 0x0, 0xf840031030, ...)
    /usr/lib/go/src/pkg/text/template/helper.go:23 +0x4e
main.main()
    /home/cox/workspace/go/src/gotutorial/templates3.go:18 +0x39d

goroutine 2 [syscall]:
created by runtime.main
    /build/buildd/golang-1/src/pkg/runtime/proc.c:221
exit status 2

标签: none

评论已关闭