Go language standard library - template
Template and rendering
In some Web architectures where the front and back ends are not separated, we usually need to render some data into HTML documents at the back end, so as to achieve the effect of dynamic Web pages (the layout and style of Web pages are roughly the same, but the displayed contents are different).
The template we mentioned here can be understood as a pre-defined HTML document file, and the function mechanism of template rendering can be simply understood as text replacement operation - using corresponding data to replace the pre prepared tags in the HTML document.
Various template engines are used in Web frameworks of many programming languages, such as jinja2 template engine used in flash framework in Python language.
Simply put, rendering is to display the data in the back-end variables in the front-end html page
(1) Use of template engine
Go language has built-in text template engine text/template and html/template for HTML documents. Their mechanism of action can be summarized as follows:
- Template files are usually defined as tmpl and tpl is a suffix (other suffixes can also be used), and UTF8 coding must be used.
- The template file uses {{and}} packages and identifies the data that needs to be passed in.
- Such data can be passed to the template through the dot (.) If the data is complex type data, its fields can be accessed through {{. FieldName}}.
- Except the contents of {{and}} packages, other contents are not modified and output as is.
(the usage is similar to that of the Flask framework in python, except that the rendering needs to be divided into several small steps)
1. Define template file
The Go language will have an extension of tmpl and tpl file as template file
In essence, the template file is still an html file, just passing the data to be passed in through {{.}} package
// . tmpl file <!DOCTYPE html> <html lang="zh-CN"> <head><title>hello, this is a title</title></head> <body> <p>this is {{.}}</p> </body> </html>
2. Parse template file
func (t *Template) Parse(src string) (*Template, error) func ParseFiles(filenames ...string) (*Template, error) func ParseGlob(pattern string) (*Template, error)
Writing method of analytic function:
①
t, err := template.ParseFiles("./hello.tmpl")
②
t, err := template.New("hello.tmpl").ParseFiles("./hello.tmpl")
Note that the parameters of the New function must be consistent with the tmpl file name to be parsed!!
3. Render template file
That is, {{.}} in the template file Render with passed in variables
func (t *Template) Execute(wr io.Writer, data interface{}) error func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error
- Example: use Go standard library "net/http" to realize template rendering
package main import ( "fmt" "html/template" "net/http" ) func sayHello(w http.ResponseWriter, r *http.Request) { //2. Parse template parse t, err := template.ParseFiles("./hello.tmpl") if err != nil { fmt.Printf("parse template faild, err: %v", err) return } //3. Render template - Execute name := "princeling" err = t.Execute(w, name) if err != nil { fmt.Printf("parse template faild, err: %v", err) return } } func main() { http.HandleFunc("/", sayHello) err := http.ListenAndServe(":9000", nil) if err != nil { fmt.Printf("http server start faild, err: %v", err) return } }
(2) Template syntax
1. {{ . }}
① When you pass in a structure, you can use Field to access the field content of the structure
type UserInfo struct { Name string gender string Age int }
<!DOCTYPE html> <html lang="zh-CN"> <head><title>hello, this is a title</title></head> <body> <p>name:{{.Name}}</p> <p>Age:{{.Age}}</p> <p>Gender:{{.gender}}</p> </body> </html>
Note: when the initial letter of a field in Golang is lowercase, it means private, and external functions and methods cannot be accessed. Therefore, other values in this example will not appear in the website
② When the passed in variable is map, it can be passed in the template file key
Note: because the key name in the map is a string, it can be obtained regardless of the case of the initial letter
③ If you want to pass multiple parameters into Execute function, you can nest these parameters into a map
user1 := UserInfo{Name: "Tom1", gender: "female1", Age: 181} m1 := map[string]interface{} { "Name": "Tom2", "Gender": "female2", "Age": 182, "fuck": "Golang", } t.Execute(w, map[string]interface{} { "m1" : m1, "user1" : user1, })
Yes In the tmpl file, you should first take values from the master map, and then take values from their respective structures
<!DOCTYPE html> <html lang="zh-CN"> <head><title>hello, this is a title</title></head> <body> <p>name:{{.m1.Name}}</p> <p>Age:{{.user1.Age}}</p> <p>Gender:{{.m1.Gender}}</p> </body> </html>
2. Notes
{{/* a comment */}} It will be ignored during execution and can be wrapped directly Comments cannot be nested and must start and end close to the delimiter
3.pipeline
pipeline refers to the operation that generates data. For example, {{.}} {. Name}} etc. The template syntax of Go supports the use of pipe symbols | to link multiple commands. The usage is similar to that of pipes under unix: | the previous command will pass the operation result (or return value) to the last position of the next command.
**Note: * * is not a pipeline only when | is used. In the template syntax of Go, the concept of pipeline is to transfer data. As long as data can be generated, it is pipeline.
4. Declare variables
You can also declare variables in the template to save the data passed into the template or the results generated by other statements
<p>{{ $age := .user1.Age }}</p> <p>{{ $age }}</p>
Where $age is the name of the variable, which can be used in subsequent code, but note that the variable name is $age, not age. To add the dollar sign$
5. Remove spaces
Sometimes, when using template syntax, some spaces or line breaks will be introduced. At this time, you can use {{- syntax to remove all blank symbols on the left of template content, and use -}} to remove all blank symbols on the right of template content
<p>name: {{- .m1.Name -}}</p> <p>Age:{{.user1.Age}}</p> <p>Gender: {{- .m1.Gender -}}</p>
Note: - be next to {{and}}, and - be separated from the template value by a space.
6. Condition judgment
Go language in There are the following conditions in tmpl files:
{{if pipeline}} T1 {{end}} {{if pipeline}} T1 {{else}} T0 {{end}} {{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
7. Comparison function collocation condition judgment
Boolean functions treat any type of zero as false and the rest as true.
The following is a collection of binary comparison operations defined as functions:
eq If arg1 == arg2 Returns true ne If arg1 != arg2 Returns true lt If arg1 < arg2 Returns true le If arg1 <= arg2 Returns true gt If arg1 > arg2 Returns true ge If arg1 >= arg2 Returns true
- In order to simplify multi parameter equality detection, eq (only eq) can accept 2 or more parameters. It will compare the first parameter with other parameters in turn and return the results of the following formula:
{{eq arg1 arg2 arg3}}
- The comparison function is only applicable to basic types (or redefined basic types, such as "type Celsius float32"). However, integers and floating-point numbers cannot be compared with each other.
Specific syntax:
{{if lt .user1.Age 18}} <p>study hard!</p> {{else}} <p>Work hard</p> {{end}}
Note that the comparison function name is written in the front, followed by the two variables to be compared
8.range function - traversal
In the template syntax of Go, the range keyword is used for traversal, which can be written in the following two ways. The value of pipeline must be array, slice, dictionary or channel
{{range pipeline}} T1 {{end}} If pipeline Its length is 0 and there will be no output {{range pipeline}} T1 {{else}} T0 {{end}} If pipeline If its length is 0, the T0.
give an example:
First, in the step of rendering the template, a slice r1 is passed to the front end
t.Execute(w, map[string]interface{} { "m1" : m1, "user1" : user1, "r1" : []string{ "football", "basketball", "tennis", }, })
Use the range function in the tmpl file to traverse the print
{{range $index, $values := .r1}} <p>{{$index}} - {{$values}}</p> {{end}}
result:
0 - football 1 - basketball 2 - tennis
9.with - declare scope
with can be changed in the tmpl file Scope, simplify code
{{with .m1}} {{.Name}} {{.Age}} {{end}}
Between with and end Are replaced with m1. So you can access the M1 field directly with one point
10. Customize functions in the template
http.HandleFunc("/", f1)
① First, define the custom function in the f1 function to be executed
k := func(name string)(string, error) { return name + "How handsome!", nil }
Note: Golang stipulates that the custom function here either has only one return value or has a return value + error (error)
② Add this custom function to the template before parsing it
t := template.New("hello.tmpl") //Create template object (unresolved, not rendered) t.Funcs(template.FuncMap{ "func_kua": k, //Finally, use "func_kua" as the custom function name in the template })
Note: first use the New function to create a template object (not parsed or rendered), and then use the Funcs function to add this function through special syntax, named "func_kua"
③ ④ parsing template and rendering template
//Parsing template _, err := t.ParseFiles("./hello.tmpl") //Resolve template object t if err != nil { fmt.Printf("template parse failed, err: %v", err) return } //Render template name := "Tom" t.Execute(w, name) //Render template object t
⑤ Using custom functions in tmpl files
<body> {{func_kua .}} </body>
Function name + parameter
11. Nested template
- You can nest other templates in the template
- This template can be a separate file or a template defined through define
Example: Hello The tmpl file is as follows
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>tmpl test</title> </head> <body> <h1>Test nesting template grammar</h1> <hr> {{template "ul.tmpl"}} <hr> {{template "ol.tmpl"}} </body> </html> {{ define "ol.tmpl"}} <ol> <li>having dinner</li> <li>sleep</li> <li>Beat beans</li> </ol> {{end}}
ul. The contents of the tmpl file are as follows:
<ul> <li>notes</li> <li>journal</li> <li>test</li> </ul>
-
There are three tmpl template files in total, the first is based on Hello tmpl; The second one is UL defined in hello tmpl; The third is independent UL Tmpl file
-
By 1 As described above, you only need to parse and render the two tmpl files hello and ul
http.HandleFunc("/tmplDemo", demo1) func demo1(w http.ResponseWriter, r *http.Request) { //Parsing template t, err := template.ParseFiles("./hello.tmpl", "./ul.tmpl") if err != nil { fmt.Printf("template parse failed, err: %v", err) return } //Render template name := "Tom" t.Execute(w, name) }
be careful!!! When ParseFiles function parses multiple tmpl files, the parent template file must be in front and its child template file must be in the back!!!! Pay attention to the order
Visit 127.0.0.1:9000/tmplDemo
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-hvHhCeyu-1627203612309)(C:\Users \ Lu Chaoyang \ appdata \ roaming \ typora user images \ image-20210725151636131. PNG)]
12.Block - inheritance (similar block settings exist in Flask)
Most websites have several similar sub pages. They only have different basic contents. Others, such as navigation bar and sidebar, are exactly the same.
To achieve this in actual programming, instead of writing the html(tmpl) file of each sub web page from beginning to end, use the block inheritance function to specify a root template base Tmpl, the rest of the sub pages are inherited from this template.
In this way, by modifying the content of the root template, you can quickly maintain and upgrade a large number of web pages instead of modifying them one by one.
① Root template base Tmpl code
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>Template inheritance</title> <style> * { margin: 0; } .nav { height: 50px; width: 100%; position: fixed; top: 0; background-color: burlywood; } .main { margin-top: 50px; } .menu { width: 20%; height: 100%; position: fixed; left: 0; background-color: cornflowerblue; } .center { text-align: center; } </style> </head> <body> <div class="nav"></div> <div class="main"> <div class="menu"></div> <div class="content center"> {{block "unfilled" .}}{{end}} </div> </div> </body> </html>
Where {{block "unfilled"}} {{end}} is the part that can be replaced by the sub template
- This part is named unfilled
- After unfilled, you need to Passed in for use by sub templates
② Sub template index Tmpl code
{{/*1.Inherit root template*/}} {{template "base.tmpl"}} {{/*2.Redefine block*/}} {{define "unfilled"}} <h1>This is index page</h1> <p>hello {{.}}</p> {{end}}
③ Analysis and rendering of sub templates in the main function
http.HandleFunc("/index_new", index_new) func index_new(w http.ResponseWriter, r *http.Request) { //Parsing template t, err := template.ParseFiles("./template/base.tmpl", "./template/index.tmpl") if err != nil { fmt.Printf("template parse failed, err: %v", err) } //Render template name := "Tom" t.Execute(w, name) }
Note: because the sub template inherits the root template, both the root and sub templates need to be parsed and rendered
③ Another way to write the main function
func home_new(w http.ResponseWriter, r *http.Request) { //Parsing template t, err := template.ParseFiles("./template/base.tmpl", "./template/home.tmpl") if err != nil { fmt.Printf("template parse failed, err: %v", err) } //Render template name := "Tom" t.ExecuteTemplate(w, "home.tmpl", name) }
When the main function uses the ExecuteTemplate method to render only the sub template home, the parameters in the root template must be inherited at the time of inheritance. The specific code is: (there must be a point at the end of the first step.)
{{/*1.Inherit root template*/}} {{template "base.tmpl" .}} {{/*2.Redefine block*/}} {{define "unfilled"}} <h1>This is home page</h1> <p>hello {{.}}</p> {{end}}
④ Supplement
If our template names conflict, for example, an index is defined under different business lines Tmpl template can be solved by the following two methods.
- Use the {{define template name}} statement at the beginning of the template file to explicitly name the template.
- You can store the template files in different directories under the Templates folder, and then use template Parseglobe ("templates / * * / *. Tmpl") parses templates. (regular matching)
13. Modify the default identifier
The template engine of the Go standard library uses curly braces {and}} as identifiers, and many front-end frameworks (such as Vue and AngularJS) also use {and}} as identifiers. Therefore, when we use the Go language template engine and the above front-end frameworks at the same time, there will be a conflict. At this time, we need to modify the identifier: modify the front-end identifier or modify the Go language identifier
template.New("test").Delims("{[", "]}").ParseFiles("./t.tmpl")
Example: want to use {[.]} To identify variables
t, err := template.New("index.tmpl").Delims("{[", "]}").ParseFiles("./index.tmpl")