Source File
template.go
Belonging Package
html/template
// Copyright 2011 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package templateimport ()// Template is a specialized Template from "text/template" that produces a safe// HTML document fragment.type Template struct {// Sticky error if escaping fails, or escapeOK if succeeded.escapeErr error// We could embed the text/template field, but it's safer not to because// we need to keep our version of the name space and the underlying// template's in sync.text *template.Template// The underlying template's parse tree, updated to be HTML-safe.Tree *parse.Tree*nameSpace // common to all associated templates}// escapeOK is a sentinel value used to indicate valid escaping.var escapeOK = fmt.Errorf("template escaped correctly")// nameSpace is the data structure shared by all templates in an association.type nameSpace struct {mu sync.Mutexset map[string]*Templateescaped boolesc escaper}// Templates returns a slice of the templates associated with t, including t// itself.func ( *Template) () []*Template {:= .nameSpace.mu.Lock()defer .mu.Unlock()// Return a slice so we don't expose the map.:= make([]*Template, 0, len(.set))for , := range .set {= append(, )}return}// Option sets options for the template. Options are described by// strings, either a simple string or "key=value". There can be at// most one equals sign in an option string. If the option string// is unrecognized or otherwise invalid, Option panics.//// Known options://// missingkey: Control the behavior during execution if a map is// indexed with a key that is not present in the map.//// "missingkey=default" or "missingkey=invalid"// The default behavior: Do nothing and continue execution.// If printed, the result of the index operation is the string// "<no value>".// "missingkey=zero"// The operation returns the zero value for the map type's element.// "missingkey=error"// Execution stops immediately with an error.func ( *Template) ( ...string) *Template {.text.Option(...)return}// checkCanParse checks whether it is OK to parse templates.// If not, it returns an error.func ( *Template) () error {if == nil {return nil}.nameSpace.mu.Lock()defer .nameSpace.mu.Unlock()if .nameSpace.escaped {return fmt.Errorf("html/template: cannot Parse after Execute")}return nil}// escape escapes all associated templates.func ( *Template) () error {.nameSpace.mu.Lock()defer .nameSpace.mu.Unlock().nameSpace.escaped = trueif .escapeErr == nil {if .Tree == nil {return fmt.Errorf("template: %q is an incomplete or empty template", .Name())}if := escapeTemplate(, .text.Root, .Name()); != nil {return}} else if .escapeErr != escapeOK {return .escapeErr}return nil}// Execute applies a parsed template to the specified data object,// writing the output to wr.// If an error occurs executing the template or writing its output,// execution stops, but partial results may already have been written to// the output writer.// A template may be executed safely in parallel, although if parallel// executions share a Writer the output may be interleaved.func ( *Template) ( io.Writer, any) error {if := .escape(); != nil {return}return .text.Execute(, )}// ExecuteTemplate applies the template associated with t that has the given// name to the specified data object and writes the output to wr.// If an error occurs executing the template or writing its output,// execution stops, but partial results may already have been written to// the output writer.// A template may be executed safely in parallel, although if parallel// executions share a Writer the output may be interleaved.func ( *Template) ( io.Writer, string, any) error {, := .lookupAndEscapeTemplate()if != nil {return}return .text.Execute(, )}// lookupAndEscapeTemplate guarantees that the template with the given name// is escaped, or returns an error if it cannot be. It returns the named// template.func ( *Template) ( string) ( *Template, error) {.nameSpace.mu.Lock()defer .nameSpace.mu.Unlock().nameSpace.escaped = true= .set[]if == nil {return nil, fmt.Errorf("html/template: %q is undefined", )}if .escapeErr != nil && .escapeErr != escapeOK {return nil, .escapeErr}if .text.Tree == nil || .text.Root == nil {return nil, fmt.Errorf("html/template: %q is an incomplete template", )}if .text.Lookup() == nil {panic("html/template internal error: template escaping out of sync")}if .escapeErr == nil {= escapeTemplate(, .text.Root, )}return ,}// DefinedTemplates returns a string listing the defined templates,// prefixed by the string "; defined templates are: ". If there are none,// it returns the empty string. Used to generate an error message.func ( *Template) () string {return .text.DefinedTemplates()}// Parse parses text as a template body for t.// Named template definitions ({{define ...}} or {{block ...}} statements) in text// define additional templates associated with t and are removed from the// definition of t itself.//// Templates can be redefined in successive calls to Parse,// before the first use of [Template.Execute] on t or any associated template.// A template definition with a body containing only white space and comments// is considered empty and will not replace an existing template's body.// This allows using Parse to add new named template definitions without// overwriting the main template body.func ( *Template) ( string) (*Template, error) {if := .checkCanParse(); != nil {return nil,}, := .text.Parse()if != nil {return nil,}// In general, all the named templates might have changed underfoot.// Regardless, some new ones may have been defined.// The template.Template set has been updated; update ours..nameSpace.mu.Lock()defer .nameSpace.mu.Unlock()for , := range .Templates() {:= .Name():= .set[]if == nil {= .new()}.text =.Tree = .Tree}return , nil}// AddParseTree creates a new template with the name and parse tree// and associates it with t.//// It returns an error if t or any associated template has already been executed.func ( *Template) ( string, *parse.Tree) (*Template, error) {if := .checkCanParse(); != nil {return nil,}.nameSpace.mu.Lock()defer .nameSpace.mu.Unlock(), := .text.AddParseTree(, )if != nil {return nil,}:= &Template{nil,,.Tree,.nameSpace,}.set[] =return , nil}// Clone returns a duplicate of the template, including all associated// templates. The actual representation is not copied, but the name space of// associated templates is, so further calls to [Template.Parse] in the copy will add// templates to the copy but not to the original. [Template.Clone] can be used to prepare// common templates and use them with variant definitions for other templates// by adding the variants after the clone is made.//// It returns an error if t has already been executed.func ( *Template) () (*Template, error) {.nameSpace.mu.Lock()defer .nameSpace.mu.Unlock()if .escapeErr != nil {return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", .Name())}, := .text.Clone()if != nil {return nil,}:= &nameSpace{set: make(map[string]*Template)}.esc = makeEscaper():= &Template{nil,,.Tree,,}.set[.Name()] =for , := range .Templates() {:= .Name():= .set[]if == nil || .escapeErr != nil {return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", .Name())}.Tree = .Tree.Copy().set[] = &Template{nil,,.Tree,.nameSpace,}}// Return the template associated with the name of this template.return .set[.Name()], nil}// New allocates a new HTML template with the given name.func ( string) *Template {:= &nameSpace{set: make(map[string]*Template)}.esc = makeEscaper():= &Template{nil,template.New(),nil,,}.set[] =return}// New allocates a new HTML template associated with the given one// and with the same delimiters. The association, which is transitive,// allows one template to invoke another with a {{template}} action.//// If a template with the given name already exists, the new HTML template// will replace it. The existing template will be reset and disassociated with// t.func ( *Template) ( string) *Template {.nameSpace.mu.Lock()defer .nameSpace.mu.Unlock()return .new()}// new is the implementation of New, without the lock.func ( *Template) ( string) *Template {:= &Template{nil,.text.New(),nil,.nameSpace,}if , := .set[]; {:= New(.Name())* = *}.set[] =return}// Name returns the name of the template.func ( *Template) () string {return .text.Name()}type FuncMap = template.FuncMap// Funcs adds the elements of the argument map to the template's function map.// It must be called before the template is parsed.// It panics if a value in the map is not a function with appropriate return// type. However, it is legal to overwrite elements of the map. The return// value is the template, so calls can be chained.func ( *Template) ( FuncMap) *Template {.text.Funcs(template.FuncMap())return}// Delims sets the action delimiters to the specified strings, to be used in// subsequent calls to [Template.Parse], [ParseFiles], or [ParseGlob]. Nested template// definitions will inherit the settings. An empty delimiter stands for the// corresponding default: {{ or }}.// The return value is the template, so calls can be chained.func ( *Template) (, string) *Template {.text.Delims(, )return}// Lookup returns the template with the given name that is associated with t,// or nil if there is no such template.func ( *Template) ( string) *Template {.nameSpace.mu.Lock()defer .nameSpace.mu.Unlock()return .set[]}// 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.New("name").Parse("html"))func ( *Template, error) *Template {if != nil {panic()}return}// ParseFiles creates a new [Template] and parses the template definitions from// the named files. The returned template's name will have the (base) name and// (parsed) contents of the first file. There must be at least one file.// If an error occurs, parsing stops and the returned [*Template] is nil.//// When parsing multiple files with the same name in different directories,// the last one mentioned will be the one that results.// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template// named "foo", while "a/foo" is unavailable.func ( ...string) (*Template, error) {return parseFiles(nil, readFileOS, ...)}// ParseFiles parses the named files and associates the resulting templates with// t. If an error occurs, parsing stops and the returned template is nil;// otherwise it is t. There must be at least one file.//// When parsing multiple files with the same name in different directories,// the last one mentioned will be the one that results.//// ParseFiles returns an error if t or any associated template has already been executed.func ( *Template) ( ...string) (*Template, error) {return parseFiles(, readFileOS, ...)}// parseFiles is the helper for the method and function. If the argument// template is nil, it is created from the first file.func ( *Template, func(string) (string, []byte, error), ...string) (*Template, error) {if := .checkCanParse(); != nil {return nil,}if len() == 0 {// Not really a problem, but be consistent.return nil, fmt.Errorf("html/template: no files named in call to ParseFiles")}for , := range {, , := ()if != nil {return nil,}:= string()// First template becomes return value if not already defined,// and we use that one for subsequent New calls to associate// all the templates together. Also, if this file has the same name// as t, this file becomes the contents of t, so// t, err := New(name).Funcs(xxx).ParseFiles(name)// works. Otherwise we create a new template associated with t.var *Templateif == nil {= New()}if == .Name() {=} else {= .New()}_, = .Parse()if != nil {return nil,}}return , nil}// ParseGlob creates a new [Template] and parses the template definitions from// the files identified by the pattern. The files are matched according to the// semantics of filepath.Match, and the pattern must match at least one file.// The returned template will have the (base) name and (parsed) contents of the// first file matched by the pattern. ParseGlob is equivalent to calling// [ParseFiles] with the list of files matched by the pattern.//// When parsing multiple files with the same name in different directories,// the last one mentioned will be the one that results.func ( string) (*Template, error) {return parseGlob(nil, )}// ParseGlob parses the template definitions in the files identified by the// pattern and associates the resulting templates with t. The files are matched// according to the semantics of filepath.Match, and the pattern must match at// least one file. ParseGlob is equivalent to calling t.ParseFiles with the// list of files matched by the pattern.//// When parsing multiple files with the same name in different directories,// the last one mentioned will be the one that results.//// ParseGlob returns an error if t or any associated template has already been executed.func ( *Template) ( string) (*Template, error) {return parseGlob(, )}// parseGlob is the implementation of the function and method ParseGlob.func ( *Template, string) (*Template, error) {if := .checkCanParse(); != nil {return nil,}, := filepath.Glob()if != nil {return nil,}if len() == 0 {return nil, fmt.Errorf("html/template: pattern matches no files: %#q", )}return parseFiles(, readFileOS, ...)}// 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 ( any) (, bool) {return template.IsTrue()}// ParseFS is like [ParseFiles] or [ParseGlob] but reads from the file system fs// instead of the host operating system's file system.// It accepts a list of glob patterns.// (Note that most file names serve as glob patterns matching only themselves.)func ( fs.FS, ...string) (*Template, error) {return parseFS(nil, , )}// ParseFS is like [Template.ParseFiles] or [Template.ParseGlob] but reads from the file system fs// instead of the host operating system's file system.// It accepts a list of glob patterns.// (Note that most file names serve as glob patterns matching only themselves.)func ( *Template) ( fs.FS, ...string) (*Template, error) {return parseFS(, , )}func ( *Template, fs.FS, []string) (*Template, error) {var []stringfor , := range {, := fs.Glob(, )if != nil {return nil,}if len() == 0 {return nil, fmt.Errorf("template: pattern matches no files: %#q", )}= append(, ...)}return parseFiles(, readFileFS(), ...)}func ( string) ( string, []byte, error) {= filepath.Base(), = os.ReadFile()return}func ( fs.FS) func(string) (string, []byte, error) {return func( string) ( string, []byte, error) {= path.Base(), = fs.ReadFile(, )return}}
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)