Documentation ¶
Overview ¶
Package template implements the interface common to the standard packages "text/template" and "html/template" as type Template.
Thus, it exploits the fact, that
package html/template provides the same interface as package text/template and should be used instead of text/template whenever the output is HTML as it automatically secures HTML output against certain attacks.
as said in go doc text/template and go doc html/template.
All methods and all package level functions are forewarded.
Instead of a single New(name) this package unsurprisingly provides two constructors:
- template.Text(name) &
- template.HTML(name).
Note: The package level functions ParseFiles & ParseGlob became
- ParseTextFiles / ParseHTMLfile resp.
- ParseTextGlob / ParseHTMLglob.
Thus, the exported type Template represents the template used, be it html or text.
Also the type FuncMap is forwarded.
Note: Clients in need to access any other type
- such as ExecError (from "text/template") or
- data types such as HTML, CSS, JS and friends
- as well as Error and ErrorCode (from "html/template")
are requested to use the respective standard package directly for access to the error and data types.
For example escape_test.go uses
import( data "html/template" )
and refers to
data.HTML, data.CSS, data.JS ...
later.
Index ¶
- func HTMLEscape(w io.Writer, b []byte)
- func HTMLEscapeString(s string) string
- func HTMLEscaper(args ...interface{}) string
- func IsTrue(val interface{}) (truth, ok bool)
- func JSEscape(w io.Writer, b []byte)
- func JSEscapeString(s string) string
- func JSEscaper(args ...interface{}) string
- func URLQueryEscaper(args ...interface{}) string
- type FuncMap
- type Template
- func HTML(Name string) Template
- func Must(t Template, err error) Template
- func ParseHTMLfiles(filenames ...string) (Template, error)
- func ParseHTMLglob(pattern string) (Template, error)
- func ParseTextFiles(filenames ...string) (Template, error)
- func ParseTextGlob(pattern string) (Template, error)
- func Text(Name string) Template
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func HTMLEscape ¶
HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
func HTMLEscapeString ¶
HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
func HTMLEscaper ¶
func HTMLEscaper(args ...interface{}) string
HTMLEscaper returns the escaped HTML equivalent of the textual representation of its arguments.
func IsTrue ¶
func IsTrue(val interface{}) (truth, ok bool)
IsTrue reports whether the value is 'true', in the sense of not the zero of its type, and whether the value has a meaningful truth value. This is the definition of truth used by if and other such actions.
func JSEscapeString ¶
JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
func JSEscaper ¶
func JSEscaper(args ...interface{}) string
JSEscaper returns the escaped JavaScript equivalent of the textual representation of its arguments.
func URLQueryEscaper ¶
func URLQueryEscaper(args ...interface{}) string
URLQueryEscaper returns the escaped value of the textual representation of its arguments in a form suitable for embedding in a URL query.
Types ¶
type FuncMap ¶
type FuncMap map[string]interface{}
FuncMap is the type of the map defining the mapping from names to functions. Each function must have either a single return value, or two return values of which the second has type error. In that case, if the second (error) return value evaluates to non-nil during execution, execution terminates and Execute returns that error.
When template execution invokes a function with an argument list, that list must be assignable to the function's parameter types. Functions meant to apply to arguments of arbitrary type can use parameters of type interface{} or of type reflect.Value. Similarly, functions meant to return a result of arbitrary type can return interface{} or reflect.Value.
type Template ¶
type Template interface { AddParseTree(name string, tree *parse.Tree) (Template, error) Clone() (Template, error) DefinedTemplates() string Delims(left, right string) Template Execute(wr io.Writer, data interface{}) error ExecuteTemplate(wr io.Writer, name string, data interface{}) error Funcs(funcMap map[string]interface{}) Template Lookup(name string) Template Name() string New(name string) Template Option(opt ...string) Template Parse(text string) (Template, error) ParseFiles(filenames ...string) (Template, error) ParseGlob(pattern string) (Template, error) Templates() []Template }
Template represents the template used (html or text).
For documentation of these methods please refer to the respective underlying standard package, e.g. `go doc text/template Parse` or `go doc html/template ExecuteTemplate`.
Example (Autoescaping) ¶
package main import ( "log" "os" "github.com/GoLangsam/template" ) func main() { check := func(err error) { if err != nil { log.Fatal(err) } } t, err := template.HTML("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) check(err) err = t.ExecuteTemplate(os.Stdout, "T", "<script>alert('you have been pwned')</script>") check(err) }
Output: Hello, <script>alert('you have been pwned')</script>!
Example (Block) ¶
package main import ( "log" "os" "strings" "github.com/GoLangsam/template" ) func main() { const ( master = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}` overlay = `{{define "list"}} {{join . ", "}}{{end}} ` ) var ( funcs = template.FuncMap{"join": strings.Join} guardians = []string{"Gamora", "Groot", "Nebula", "Rocket", "Star-Lord"} ) masterTmpl, err := template.HTML("master").Funcs(funcs).Parse(master) if err != nil { log.Fatal(err) } overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(overlay) if err != nil { log.Fatal(err) } if err := masterTmpl.Execute(os.Stdout, guardians); err != nil { log.Fatal(err) } if err := overlayTmpl.Execute(os.Stdout, guardians); err != nil { log.Fatal(err) } }
Output: Names: - Gamora - Groot - Nebula - Rocket - Star-Lord Names: Gamora, Groot, Nebula, Rocket, Star-Lord
Example (Escape) ¶
package main import ( "fmt" "os" "github.com/GoLangsam/template" ) func main() { const s = `"Fran & Freddie's Diner" <tasty@example.com>` v := []interface{}{`"Fran & Freddie's Diner"`, ' ', `<tasty@example.com>`} fmt.Println(template.HTMLEscapeString(s)) template.HTMLEscape(os.Stdout, []byte(s)) fmt.Fprintln(os.Stdout, "") fmt.Println(template.HTMLEscaper(v...)) fmt.Println(template.JSEscapeString(s)) template.JSEscape(os.Stdout, []byte(s)) fmt.Fprintln(os.Stdout, "") fmt.Println(template.JSEscaper(v...)) fmt.Println(template.URLQueryEscaper(v...)) }
Output: "Fran & Freddie's Diner" <tasty@example.com> "Fran & Freddie's Diner" <tasty@example.com> "Fran & Freddie's Diner"32<tasty@example.com> \"Fran & Freddie\'s Diner\" \x3Ctasty@example.com\x3E \"Fran & Freddie\'s Diner\" \x3Ctasty@example.com\x3E \"Fran & Freddie\'s Diner\"32\x3Ctasty@example.com\x3E %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
Example (Func) ¶
This example demonstrates a custom function to process template text. It installs the strings.Title function and uses it to Make Title Text Look Good In Our Template's Output.
package main import ( "log" "os" "strings" "github.com/GoLangsam/template" ) func main() { // First we create a FuncMap with which to register the function. funcMap := template.FuncMap{ // The name "title" is what the function will be called in the template text. "title": strings.Title, } // A simple template definition to test our function. // We print the input text several ways: // - the original // - title-cased // - title-cased and then printed with %q // - printed with %q and then title-cased. const templateText = ` Input: {{printf "%q" .}} Output 0: {{title .}} Output 1: {{title . | printf "%q"}} Output 2: {{printf "%q" . | title}} ` // Create a template, add the function map, and parse the text. tmpl, err := template.Text("titleTest").Funcs(funcMap).Parse(templateText) if err != nil { log.Fatalf("parsing: %s", err) } // Run the template to verify the output. err = tmpl.Execute(os.Stdout, "the go programming language") if err != nil { log.Fatalf("execution: %s", err) } }
Output: Input: "the go programming language" Output 0: The Go Programming Language Output 1: "The Go Programming Language" Output 2: "The Go Programming Language"
Example (Glob) ¶
Here we demonstrate loading a set of templates from a directory.
package main import ( "io" "io/ioutil" "log" "os" "path/filepath" "github.com/GoLangsam/template" ) // templateFile defines the contents of a template to be stored in a file, for testing. type templateFile struct { name string contents string } func createTestDir(files []templateFile) string { dir, err := ioutil.TempDir("", "template") if err != nil { log.Fatal(err) } for _, file := range files { f, err := os.Create(filepath.Join(dir, file.name)) if err != nil { log.Fatal(err) } defer f.Close() _, err = io.WriteString(f, file.contents) if err != nil { log.Fatal(err) } } return dir } func main() { // Here we create a temporary directory and populate it with our sample // template definition files; usually the template files would already // exist in some location known to the program. dir := createTestDir([]templateFile{ // T0.tmpl is a plain template file that just invokes T1. {"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`}, // T1.tmpl defines a template, T1 that invokes T2. {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, // T2.tmpl defines a template T2. {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, }) // Clean up after the test; another quirk of running as an example. defer os.RemoveAll(dir) // pattern is the glob pattern used to find all the template files. pattern := filepath.Join(dir, "*.tmpl") // Here starts the example proper. // T0.tmpl is the first name matched, so it becomes the starting template, // the value returned by ParseGlob. tmpl := template.Must(template.ParseHTMLglob(pattern)) err := tmpl.Execute(os.Stdout, nil) if err != nil { log.Fatalf("template execution: %s", err) } }
Output: T0 invokes T1: (T1 invokes T2: (This is T2))
Example (Helpers) ¶
This example demonstrates one way to share some templates and use them in different contexts. In this variant we add multiple driver templates by hand to an existing bundle of templates.
package main import ( "io" "io/ioutil" "log" "os" "path/filepath" "github.com/GoLangsam/template" ) // templateFile defines the contents of a template to be stored in a file, for testing. type templateFile struct { name string contents string } func createTestDir(files []templateFile) string { dir, err := ioutil.TempDir("", "template") if err != nil { log.Fatal(err) } for _, file := range files { f, err := os.Create(filepath.Join(dir, file.name)) if err != nil { log.Fatal(err) } defer f.Close() _, err = io.WriteString(f, file.contents) if err != nil { log.Fatal(err) } } return dir } func main() { // Here we create a temporary directory and populate it with our sample // template definition files; usually the template files would already // exist in some location known to the program. dir := createTestDir([]templateFile{ // T1.tmpl defines a template, T1 that invokes T2. {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, // T2.tmpl defines a template T2. {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, }) // Clean up after the test; another quirk of running as an example. defer os.RemoveAll(dir) // pattern is the glob pattern used to find all the template files. pattern := filepath.Join(dir, "*.tmpl") // Here starts the example proper. // Load the helpers. templates := template.Must(template.ParseHTMLglob(pattern)) // Add one driver template to the bunch; we do this with an explicit template definition. _, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}") if err != nil { log.Fatal("parsing driver1: ", err) } // Add another driver template. _, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}") if err != nil { log.Fatal("parsing driver2: ", err) } // We load all the templates before execution. This package does not require // that behavior but html/template's escaping does, so it's a good habit. err = templates.ExecuteTemplate(os.Stdout, "driver1", nil) if err != nil { log.Fatalf("driver1 execution: %s", err) } err = templates.ExecuteTemplate(os.Stdout, "driver2", nil) if err != nil { log.Fatalf("driver2 execution: %s", err) } }
Output: Driver 1 calls T1: (T1 invokes T2: (This is T2)) Driver 2 calls T2: (This is T2)
Example (Html) ¶
package main import ( "log" "os" "github.com/GoLangsam/template" ) func main() { const tpl = ` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>{{.Title}}</title> </head> <body> {{range .Items}}<div>{{ . }}</div>{{else}}<div><strong>no rows</strong></div>{{end}} </body> </html>` check := func(err error) { if err != nil { log.Fatal(err) } } t, err := template.HTML("webpage").Parse(tpl) check(err) data := struct { Title string Items []string }{ Title: "My page", Items: []string{ "My photos", "My blog", }, } err = t.Execute(os.Stdout, data) check(err) noItems := struct { Title string Items []string }{ Title: "My another page", Items: []string{}, } err = t.Execute(os.Stdout, noItems) check(err) }
Output: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>My page</title> </head> <body> <div>My photos</div><div>My blog</div> </body> </html> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>My another page</title> </head> <body> <div><strong>no rows</strong></div> </body> </html>
Example (Parsefiles) ¶
Here we demonstrate loading a set of templates from files in different directories
package main import ( "io" "io/ioutil" "log" "os" "path/filepath" "github.com/GoLangsam/template" ) // templateFile defines the contents of a template to be stored in a file, for testing. type templateFile struct { name string contents string } func createTestDir(files []templateFile) string { dir, err := ioutil.TempDir("", "template") if err != nil { log.Fatal(err) } for _, file := range files { f, err := os.Create(filepath.Join(dir, file.name)) if err != nil { log.Fatal(err) } defer f.Close() _, err = io.WriteString(f, file.contents) if err != nil { log.Fatal(err) } } return dir } func main() { // Here we create different temporary directories and populate them with our sample // template definition files; usually the template files would already // exist in some location known to the program. dir1 := createTestDir([]templateFile{ // T1.tmpl is a plain template file that just invokes T2. {"T1.tmpl", `T1 invokes T2: ({{template "T2"}})`}, }) dir2 := createTestDir([]templateFile{ // T2.tmpl defines a template T2. {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, }) // Clean up after the test; another quirk of running as an example. defer func(dirs ...string) { for _, dir := range dirs { os.RemoveAll(dir) } }(dir1, dir2) // Here starts the example proper. // Let's just parse only dir1/T0 and dir2/T2 paths := []string{ filepath.Join(dir1, "T1.tmpl"), filepath.Join(dir2, "T2.tmpl"), } tmpl := template.Must(template.ParseHTMLfiles(paths...)) err := tmpl.Execute(os.Stdout, nil) if err != nil { log.Fatalf("template execution: %s", err) } }
Output: T1 invokes T2: (This is T2)
Example (Text) ¶
package main import ( "log" "os" "github.com/GoLangsam/template" ) func main() { // Define a template. const letter = ` Dear {{.Name}}, {{if .Attended}} It was a pleasure to see you at the wedding. {{- else}} It is a shame you couldn't make it to the wedding. {{- end}} {{with .Gift -}} Thank you for the lovely {{.}}. {{end}} Best wishes, Josie ` // Prepare some data to insert into the template. type Recipient struct { Name, Gift string Attended bool } var recipients = []Recipient{ {"Aunt Mildred", "bone china tea set", true}, {"Uncle John", "moleskin pants", false}, {"Cousin Rodney", "", false}, } // Create a new template and parse the letter into it. t := template.Must(template.Text("letter").Parse(letter)) // Execute the template for each recipient. for _, r := range recipients { err := t.Execute(os.Stdout, r) if err != nil { log.Println("executing template:", err) } } }
Output: Dear Aunt Mildred, It was a pleasure to see you at the wedding. Thank you for the lovely bone china tea set. Best wishes, Josie Dear Uncle John, It is a shame you couldn't make it to the wedding. Thank you for the lovely moleskin pants. Best wishes, Josie Dear Cousin Rodney, It is a shame you couldn't make it to the wedding. Best wishes, Josie
func HTML ¶
HTML returns a new "html/template" Template
Example ¶
package main import ( "log" "os" "github.com/GoLangsam/template" ) func main() { const tpl = ` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>{{.Title}}</title> </head> <body> {{range .Items}}<div>{{ . }}</div>{{else}}<div><strong>no rows</strong></div>{{end}} </body> </html>` check := func(err error) { if err != nil { log.Fatal(err) } } t, err := template.HTML("webpage").Parse(tpl) check(err) data := struct { Title string Items []string }{ Title: "My page", Items: []string{ "My photos", "My blog", }, } err = t.Execute(os.Stdout, data) check(err) noItems := struct { Title string Items []string }{ Title: "My another page", Items: []string{}, } err = t.Execute(os.Stdout, noItems) check(err) }
Output: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>My page</title> </head> <body> <div>My photos</div><div>My blog</div> </body> </html> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>My another page</title> </head> <body> <div><strong>no rows</strong></div> </body> </html>
Example (Autoescaping) ¶
package main import ( "log" "os" "github.com/GoLangsam/template" ) func main() { check := func(err error) { if err != nil { log.Fatal(err) } } t, err := template.HTML("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) check(err) err = t.ExecuteTemplate(os.Stdout, "T", "<script>alert('you have been pwned')</script>") check(err) }
Output: Hello, <script>alert('you have been pwned')</script>!
Example (Block) ¶
package main import ( "log" "os" "strings" "github.com/GoLangsam/template" ) func main() { const ( master = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}` overlay = `{{define "list"}} {{join . ", "}}{{end}} ` ) var ( funcs = template.FuncMap{"join": strings.Join} guardians = []string{"Gamora", "Groot", "Nebula", "Rocket", "Star-Lord"} ) masterTmpl, err := template.HTML("master").Funcs(funcs).Parse(master) if err != nil { log.Fatal(err) } overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(overlay) if err != nil { log.Fatal(err) } if err := masterTmpl.Execute(os.Stdout, guardians); err != nil { log.Fatal(err) } if err := overlayTmpl.Execute(os.Stdout, guardians); err != nil { log.Fatal(err) } }
Output: Names: - Gamora - Groot - Nebula - Rocket - Star-Lord Names: Gamora, Groot, Nebula, Rocket, Star-Lord
Example (Escape) ¶
package main import ( "fmt" "os" "github.com/GoLangsam/template" ) func main() { const s = `"Fran & Freddie's Diner" <tasty@example.com>` v := []interface{}{`"Fran & Freddie's Diner"`, ' ', `<tasty@example.com>`} fmt.Println(template.HTMLEscapeString(s)) template.HTMLEscape(os.Stdout, []byte(s)) fmt.Fprintln(os.Stdout, "") fmt.Println(template.HTMLEscaper(v...)) fmt.Println(template.JSEscapeString(s)) template.JSEscape(os.Stdout, []byte(s)) fmt.Fprintln(os.Stdout, "") fmt.Println(template.JSEscaper(v...)) fmt.Println(template.URLQueryEscaper(v...)) }
Output: "Fran & Freddie's Diner" <tasty@example.com> "Fran & Freddie's Diner" <tasty@example.com> "Fran & Freddie's Diner"32<tasty@example.com> \"Fran & Freddie\'s Diner\" \x3Ctasty@example.com\x3E \"Fran & Freddie\'s Diner\" \x3Ctasty@example.com\x3E \"Fran & Freddie\'s Diner\"32\x3Ctasty@example.com\x3E %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
func Must ¶
Must is a helper that wraps a call to a function returning (Template, error) and panics if the error is non-nil. It is intended for use in variable initializations such as
var t = template.Must(template.NewText|HtmlTemplate("name").Parse("text"))
func ParseHTMLfiles ¶
ParseHTMLfiles wraps html/template.ParseFiles
func ParseHTMLglob ¶
ParseHTMLglob wraps html/template.ParseGlob
func ParseTextFiles ¶
ParseTextFiles wraps text/template.ParseFiles
func ParseTextGlob ¶
ParseTextGlob wraps text/template.ParseGlob
func Text ¶
Text returns a new "text/template" Template
Example (Block) ¶
package main import ( "log" "os" "strings" "github.com/GoLangsam/template" ) func main() { const ( master = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}` overlay = `{{define "list"}} {{join . ", "}}{{end}} ` ) var ( funcs = template.FuncMap{"join": strings.Join} guardians = []string{"Gamora", "Groot", "Nebula", "Rocket", "Star-Lord"} ) masterTmpl, err := template.Text("master").Funcs(funcs).Parse(master) if err != nil { log.Fatal(err) } overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(overlay) if err != nil { log.Fatal(err) } if err := masterTmpl.Execute(os.Stdout, guardians); err != nil { log.Fatal(err) } if err := overlayTmpl.Execute(os.Stdout, guardians); err != nil { log.Fatal(err) } }
Output: Names: - Gamora - Groot - Nebula - Rocket - Star-Lord Names: Gamora, Groot, Nebula, Rocket, Star-Lord
Example (Text) ¶
package main import ( "log" "os" "github.com/GoLangsam/template" ) func main() { // Define a template. const letter = ` Dear {{.Name}}, {{if .Attended}} It was a pleasure to see you at the wedding. {{- else}} It is a shame you couldn't make it to the wedding. {{- end}} {{with .Gift -}} Thank you for the lovely {{.}}. {{end}} Best wishes, Josie ` // Prepare some data to insert into the template. type Recipient struct { Name, Gift string Attended bool } var recipients = []Recipient{ {"Aunt Mildred", "bone china tea set", true}, {"Uncle John", "moleskin pants", false}, {"Cousin Rodney", "", false}, } // Create a new template and parse the letter into it. t := template.Must(template.Text("letter").Parse(letter)) // Execute the template for each recipient. for _, r := range recipients { err := t.Execute(os.Stdout, r) if err != nil { log.Println("executing template:", err) } } }
Output: Dear Aunt Mildred, It was a pleasure to see you at the wedding. Thank you for the lovely bone china tea set. Best wishes, Josie Dear Uncle John, It is a shame you couldn't make it to the wedding. Thank you for the lovely moleskin pants. Best wishes, Josie Dear Cousin Rodney, It is a shame you couldn't make it to the wedding. Best wishes, Josie