Spec-Zone.ru › Go

Пакет template

  • import "text/template"
  • Обзор
  • Указатель
  • Примеры
  • Подкаталоги

Обзор

Пакет template реализует шаблоны, управляемые данными, для генерации текстового вывода.

Для генерации HTML-вывода см. html/template: этот пакет имеет тот же интерфейс, что и данный пакет, но автоматически защищает HTML-вывод от определённых атак.

Шаблоны выполняются путём применения к структуре данных. Аннотации в шаблоне ссылаются на элементы структуры данных (обычно на поле структуры или ключ в карте), чтобы управлять выполнением и получать значения для отображения. При выполнении шаблона обходится структура, а курсору, представленному точкой «.» и называемому «точкой», по мере выполнения присваивается значение в текущем расположении структуры.

Модель безопасности, используемая этим пакетом, предполагает, что авторам шаблонов можно доверять. Пакет не выполняет автоматическое экранирование вывода, поэтому внедрение кода в шаблон может привести к произвольному выполнению кода, если шаблон выполняется из ненадёжного источника.

Входной текст шаблона — это текст в кодировке UTF-8 в любом формате. «Действия» — вычисления данных или управляющие структуры — ограничены символами «{{» и «}}»; весь текст вне действий без изменений копируется в выходные данные.

После разбора шаблон можно безопасно выполнять параллельно, хотя при совместном использовании Writer параллельными выполнениями вывод может перемешиваться.

Вот тривиальный пример, который выводит «17 items are made of wool».

type Inventory struct {
	Material string
	Count    uint
}
sweaters := Inventory{"wool", 17}
tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}")
if err != nil { panic(err) }
err = tmpl.Execute(os.Stdout, sweaters)
if err != nil { panic(err) }

Более сложные примеры приведены ниже.

Текст и пробелы

По умолчанию при выполнении шаблона весь текст между действиями копируется дословно. Например, строка « items are made of » из примера выше выводится в стандартный вывод при запуске программы.

Однако для удобства форматирования исходного кода шаблона, если за левым разделителем действия (по умолчанию «{{») сразу следуют знак минуса и пробел, из непосредственно предшествующего текста удаляются все конечные пробельные символы. Аналогично, если перед правым разделителем («}}») стоят пробел и знак минуса, из непосредственно следующего текста удаляются все начальные пробельные символы. В этих маркерах удаления пробельный символ обязателен: «{{- 3}}» подобно «{{3}}», но удаляет пробельные символы из непосредственно предшествующего текста, тогда как «{{-3}}» разбирается как действие, содержащее число -3.

Например, при выполнении шаблона с исходным текстом

"{{23 -}} < {{- 45}}"

сгенерированный вывод будет таким:

"23<45"

Для этого удаления к пробельным символам относятся те же символы, что и в Go: пробел, горизонтальная табуляция, возврат каретки и перевод строки.

Действия

Ниже приведён список действий. «Аргументы» и «конвейеры» — это вычисления данных, подробно описанные в соответствующих следующих разделах.

{{/* a comment */}}
{{- /* a comment with white space trimmed from preceding and following text */ -}}
	A comment; discarded. May contain newlines.
	Comments do not nest and must start and end at the
	delimiters, as shown here.

{{pipeline}}
	The default textual representation (the same as would be
	printed by fmt.Print) of the value of the pipeline is copied
	to the output.

{{if pipeline}} T1 {{end}}
	If the value of the pipeline is empty, no output is generated;
	otherwise, T1 is executed. The empty values are false, 0, any
	nil pointer or interface value, and any array, slice, map, or
	string of length zero.
	Dot is unaffected.

{{if pipeline}} T1 {{else}} T0 {{end}}
	If the value of the pipeline is empty, T0 is executed;
	otherwise, T1 is executed. Dot is unaffected.

{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
	To simplify the appearance of if-else chains, the else action
	of an if may include another if directly; the effect is exactly
	the same as writing
		{{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}

{{range pipeline}} T1 {{end}}
	The value of the pipeline must be an array, slice, map, iter.Seq,
	iter.Seq2, integer or channel.
	If the value of the pipeline has length zero, nothing is output;
	otherwise, dot is set to the successive elements of the array,
	slice, or map and T1 is executed. If the value is a map and the
	keys are of basic type with a defined order, the elements will be
	visited in sorted key order.

{{range pipeline}} T1 {{else}} T0 {{end}}
	The value of the pipeline must be an array, slice, map, iter.Seq,
	iter.Seq2, integer or channel.
	If the value of the pipeline has length zero, dot is unaffected and
	T0 is executed; otherwise, dot is set to the successive elements
	of the array, slice, or map and T1 is executed.

{{break}}
	The innermost {{range pipeline}} loop is ended early, stopping the
	current iteration and bypassing all remaining iterations.

{{continue}}
	The current iteration of the innermost {{range pipeline}} loop is
	stopped, and the loop starts the next iteration.

{{template "name"}}
	The template with the specified name is executed with nil data.

{{template "name" pipeline}}
	The template with the specified name is executed with dot set
	to the value of the pipeline.

{{block "name" pipeline}} T1 {{end}}
	A block is shorthand for defining a template
		{{define "name"}} T1 {{end}}
	and then executing it in place
		{{template "name" pipeline}}
	The typical use is to define a set of root templates that are
	then customized by redefining the block templates within.

{{with pipeline}} T1 {{end}}
	If the value of the pipeline is empty, no output is generated;
	otherwise, dot is set to the value of the pipeline and T1 is
	executed.

{{with pipeline}} T1 {{else}} T0 {{end}}
	If the value of the pipeline is empty, dot is unaffected and T0
	is executed; otherwise, dot is set to the value of the pipeline
	and T1 is executed.

{{with pipeline}} T1 {{else with pipeline}} T0 {{end}}
	To simplify the appearance of with-else chains, the else action
	of a with may include another with directly; the effect is exactly
	the same as writing
		{{with pipeline}} T1 {{else}}{{with pipeline}} T0 {{end}}{{end}}

Аргументы

Аргумент — это простое значение, обозначаемое одним из следующих способов.

  • Булева, строковая, символьная, целочисленная, с плавающей точкой, мнимая или комплексная константа в синтаксисе Go. Они ведут себя как нетипизированные константы Go. Обратите внимание: как и в Go, переполнение большой целочисленной константы при присваивании или передаче функции может зависеть от того, имеет ли тип int на хост-компьютере разрядность 32 или 64 бита.

  • Ключевое слово nil, представляющее нетипизированное значение nil в Go.

  • Символ «.» (точка):

    .

    Результатом является значение точки.

  • Имя переменной — возможно, пустая буквенно-цифровая строка с предшествующим знаком доллара, например

    $piOver2

    или

    $

    Результатом является значение переменной. Переменные описаны ниже.

  • Имя поля данных, которые должны быть структурой, с предшествующей точкой, например

    .Field

    Результатом является значение поля. Вызовы полей можно объединять в цепочки:

    .Field1.Field2

    Поля также можно вычислять для переменных, в том числе объединять в цепочки:

    $x.Field1.Field2

  • Имя ключа данных, которые должны быть картой, с предшествующей точкой, например

    .Key

    Результатом является значение элемента карты, полученного по ключу. Вызовы ключей можно объединять в цепочки и сочетать с полями на любую глубину:

    .Field1.Key1.Field2.Key2

    Хотя ключ должен быть буквенно-цифровым идентификатором, в отличие от имён полей он не обязан начинаться с заглавной буквы. Ключи также можно вычислять для переменных, в том числе объединять в цепочки:

    $x.key1.key2

  • Имя метода данных без аргументов с предшествующей точкой, например

    .Method

    Результатом является значение, полученное при вызове метода с точкой в качестве получателя: dot.Method(). Такой метод должен возвращать одно значение (любого типа) или два значения, второе из которых — ошибка. Если возвращаются два значения и ошибка не равна nil, выполнение прекращается, а вызывающей стороне возвращается ошибка в качестве результата Execute. Вызовы методов можно объединять в цепочки и сочетать с полями и ключами на любую глубину:

    .Field1.Key1.Method1.Field2.Key2.Method2

    Методы также можно вычислять для переменных, в том числе объединять в цепочки:

    $x.Method1.Field

  • Имя функции без аргументов, например

    fun

    Результатом является значение, полученное при вызове функции fun(). Типы и значения возвращаемых результатов ведут себя так же, как у методов. Функции и имена функций описаны ниже.

  • Заключённый в скобки вариант одного из приведённых выше выражений, используемый для группировки. К результату можно обратиться через поле или ключ карты.

    print (.F1 arg1) (.F2 arg2) (.StructValuedMethod "arg").Field

Аргументы могут вычисляться в значения любого типа; если это указатели, реализация при необходимости автоматически разыменовывает их до базового типа. Если вычисление даёт значение функции, например поле структуры с типом-функцией, функция не вызывается автоматически, но её можно использовать как логическое значение в действии if и подобных действиях. Чтобы вызвать её, используйте функцию call, описанную ниже.

Конвейеры

Конвейер — это, возможно, связанная в цепочку последовательность «команд». Команда — это простое значение (аргумент) либо вызов функции или метода, возможно, с несколькими аргументами:

Argument
	The result is the value of evaluating the argument.
.Method [Argument...]
	The method can be alone or the last element of a chain but,
	unlike methods in the middle of a chain, it can take arguments.
	The result is the value of calling the method with the
	arguments:
		dot.Method(Argument1, etc.)
functionName [Argument...]
	The result is the value of calling the function associated
	with the name:
		function(Argument1, etc.)
	Functions and function names are described below.

Конвейер можно «связать в цепочку», разделив последовательность команд символами конвейера «|». В связанном в цепочку конвейере результат каждой команды передаётся в качестве последнего аргумента следующей команды. Вывод последней команды конвейера является значением конвейера.

Команда возвращает одно или два значения, причём второе имеет тип error. Если второе значение присутствует и вычисляется в значение, отличное от nil, выполнение прекращается, а вызывающей стороне Execute возвращается ошибка.

Переменные

Конвейер внутри действия может инициализировать переменную, чтобы сохранить результат. Инициализация имеет следующий синтаксис:

$variable := pipeline

где $variable — имя переменной. Действие, объявляющее переменную, не создаёт вывода.

Ранее объявленные переменные также можно присваивать, используя следующий синтаксис:

$variable = pipeline

Если действие «range» инициализирует переменную, ей присваиваются последовательные элементы итерации. Кроме того, «range» может объявить две переменные, разделённые запятой:

range $index, $element := pipeline

в этом случае $index и $element получают последовательные значения индекса массива/среза или ключа карты и элемента соответственно. Обратите внимание: если объявлена только одна переменная, ей присваивается элемент; это противоположно соглашению в конструкциях range языка Go.

Область видимости переменной распространяется до действия «end» управляющей конструкции («if», «with» или «range»), в которой она объявлена, либо до конца шаблона, если такой управляющей конструкции нет. Вызов шаблона не наследует переменные из места вызова.

При начале выполнения $ получает аргумент данных, переданный в Execute, то есть начальное значение точки.

Примеры

Вот несколько примеров однострочных шаблонов, демонстрирующих конвейеры и переменные. Все они выводят слово «output» в кавычках:

{{"\"output\""}}
	A string constant.
{{`"output"`}}
	A raw string constant.
{{printf "%q" "output"}}
	A function call.
{{"output" | printf "%q"}}
	A function call whose final argument comes from the previous
	command.
{{printf "%q" (print "out" "put")}}
	A parenthesized argument.
{{"put" | printf "%s%s" "out" | printf "%q"}}
	A more elaborate call.
{{"output" | printf "%s" | printf "%q"}}
	A longer chain.
{{with "output"}}{{printf "%q" .}}{{end}}
	A with action using dot.
{{with $x := "output" | printf "%q"}}{{$x}}{{end}}
	A with action that creates and uses a variable.
{{with $x := "output"}}{{printf "%q" $x}}{{end}}
	A with action that uses the variable in another action.
{{with $x := "output"}}{{$x | printf "%q"}}{{end}}
	The same, but pipelined.

Функции

При выполнении функции ищутся в двух картах функций: сначала в шаблоне, затем в глобальной карте функций. По умолчанию в шаблоне не определено ни одной функции, но их можно добавить с помощью метода Funcs.

Предопределённые глобальные функции имеют следующие имена.

and
	Returns the boolean AND of its arguments by returning the
	first empty argument or the last argument. That is,
	"and x y" behaves as "if x then y else x."
	Evaluation proceeds through the arguments left to right
	and returns when the result is determined.
call
	Returns the result of calling the first argument, which
	must be a function, with the remaining arguments as parameters.
	Thus "call .X.Y 1 2" is, in Go notation, dot.X.Y(1, 2) where
	Y is a func-valued field, map entry, or the like.
	The first argument must be the result of an evaluation
	that yields a value of function type (as distinct from
	a predefined function such as print). The function must
	return either one or two result values, the second of which
	is of type error. If the arguments don't match the function
	or the returned error value is non-nil, execution stops.
html
	Returns the escaped HTML equivalent of the textual
	representation of its arguments. This function is unavailable
	in html/template, with a few exceptions.
index
	Returns the result of indexing its first argument by the
	following arguments. Thus "index x 1 2 3" is, in Go syntax,
	x[1][2][3]. Each indexed item must be a map, slice, or array.
slice
	slice returns the result of slicing its first argument by the
	remaining arguments. Thus "slice x 1 2" is, in Go syntax, x[1:2],
	while "slice x" is x[:], "slice x 1" is x[1:], and "slice x 1 2 3"
	is x[1:2:3]. The first argument must be a string, slice, or array.
js
	Returns the escaped JavaScript equivalent of the textual
	representation of its arguments.
len
	Returns the integer length of its argument.
not
	Returns the boolean negation of its single argument.
or
	Returns the boolean OR of its arguments by returning the
	first non-empty argument or the last argument, that is,
	"or x y" behaves as "if x then x else y".
	Evaluation proceeds through the arguments left to right
	and returns when the result is determined.
print
	An alias for fmt.Sprint
printf
	An alias for fmt.Sprintf
println
	An alias for fmt.Sprintln
urlquery
	Returns the escaped value of the textual representation of
	its arguments in a form suitable for embedding in a URL query.
	This function is unavailable in html/template, with a few
	exceptions.

Булевы функции считают нулевое значение ложным, а ненулевое — истинным.

Также определён набор бинарных операторов сравнения в виде функций:

eq
	Returns the boolean truth of arg1 == arg2
ne
	Returns the boolean truth of arg1 != arg2
lt
	Returns the boolean truth of arg1 < arg2
le
	Returns the boolean truth of arg1 <= arg2
gt
	Returns the boolean truth of arg1 > arg2
ge
	Returns the boolean truth of arg1 >= arg2

Для более простых проверок равенства с несколькими вариантами функция eq (только она) принимает два или более аргумента, сравнивает второй и последующие с первым и фактически возвращает

arg1==arg2 || arg1==arg3 || arg1==arg4 ...

(Однако, в отличие от оператора || в Go, eq является вызовом функции, поэтому будут вычислены все аргументы.)

Функции сравнения работают со всеми значениями, которые Go определяет как сравнимые. Для базовых типов, таких как целые числа, правила смягчены: размер и точный тип игнорируются, поэтому любое целочисленное значение, знаковое или беззнаковое, можно сравнивать с любым другим целочисленным значением. (Сравниваются арифметические значения, а не битовые представления, поэтому все отрицательные целые числа меньше всех беззнаковых целых чисел.) Однако, как обычно, нельзя сравнивать int с float32 и так далее.

Связанные шаблоны

Каждый шаблон получает имя в виде строки, указанной при его создании. Каждый шаблон также связан с нулём или более другими шаблонами, которые он может вызывать по имени; такие связи являются транзитивными и образуют пространство имён шаблонов.

Шаблон может использовать вызов шаблона, чтобы создать экземпляр другого связанного шаблона; см. объяснение действия «template» выше. Имя должно принадлежать шаблону, связанному с шаблоном, содержащим этот вызов.

Вложенные определения шаблонов

При разборе шаблона можно определить другой шаблон и связать его с разбираемым шаблоном. Определения шаблонов должны находиться на верхнем уровне шаблона, подобно глобальным переменным в программе на Go.

Синтаксис таких определений требует заключить каждое объявление шаблона между действиями «define» и «end».

Действие define задаёт имя создаваемого шаблона с помощью строковой константы. Вот простой пример:

{{define "T1"}}ONE{{end}}
{{define "T2"}}TWO{{end}}
{{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
{{template "T3"}}

Здесь определяются два шаблона, T1 и T2, и третий шаблон T3, который вызывает первые два при выполнении. Наконец, вызывается T3. При выполнении этот шаблон выведет текст

ONE TWO

По своей конструкции шаблон может находиться только в одной группе связанных шаблонов. Если шаблон должен быть доступен из нескольких таких групп, его определение необходимо разобрать несколько раз, чтобы создать отдельные значения *Template, либо скопировать с помощью Template.Clone или Template.AddParseTree.

Метод Parse можно вызывать несколько раз, чтобы собрать различные связанные шаблоны; простые способы разбора связанных шаблонов, хранящихся в файлах, см. в ParseFiles, ParseGlob, Template.ParseFiles и Template.ParseGlob.

Шаблон можно выполнить напрямую или с помощью Template.ExecuteTemplate, который выполняет связанный шаблон, указанный по имени. Чтобы вызвать приведённый выше пример, можно написать:

err := tmpl.Execute(os.Stdout, "no data needed")
if err != nil {
	log.Fatalf("execution failed: %s", err)
}

или явно вызвать конкретный шаблон по имени:

err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed")
if err != nil {
	log.Fatalf("execution failed: %s", err)
}

Указатель

  • func HTMLEscape(w io.Writer, b []byte)
  • func HTMLEscapeString(s string) string
  • func HTMLEscaper(args ...any) string
  • func IsTrue(val any) (truth, ok bool)
  • func JSEscape(w io.Writer, b []byte)
  • func JSEscapeString(s string) string
  • func JSEscaper(args ...any) string
  • func URLQueryEscaper(args ...any) string
  • type ExecError
  • func (e ExecError) Error() string
  • func (e ExecError) Unwrap() error
  • type FuncMap
  • type Template
  • func Must(t *Template, err error) *Template
  • func New(name string) *Template
  • func ParseFS(fsys fs.FS, patterns ...string) (*Template, error)
  • func ParseFiles(filenames ...string) (*Template, error)
  • func ParseGlob(pattern string) (*Template, error)
  • func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error)
  • func (t *Template) Clone() (*Template, error)
  • func (t *Template) DefinedTemplates() string
  • func (t *Template) Delims(left, right string) *Template
  • func (t *Template) Execute(wr io.Writer, data any) error
  • func (t *Template) ExecuteTemplate(wr io.Writer, name string, data any) error
  • func (t *Template) Funcs(funcMap FuncMap) *Template
  • func (t *Template) Lookup(name string) *Template
  • func (t *Template) Name() string
  • func (t *Template) New(name string) *Template
  • func (t *Template) Option(opt ...string) *Template
  • func (t *Template) Parse(text string) (*Template, error)
  • func (t *Template) ParseFS(fsys fs.FS, patterns ...string) (*Template, error)
  • func (t *Template) ParseFiles(filenames ...string) (*Template, error)
  • func (t *Template) ParseGlob(pattern string) (*Template, error)
  • func (t *Template) Templates() []*Template

Примеры

Template
Template (Block)
Template (Func)
Template (Funcs)
Template (Glob)
Template (Helpers)
Template (If)
Template (Share)

Файлы пакета

doc.go exec.go funcs.go helper.go option.go template.go

функция HTMLEscape

func HTMLEscape(w io.Writer, b []byte)

HTMLEscape записывает в w экранированный HTML-эквивалент обычных текстовых данных b.

функция HTMLEscapeString

func HTMLEscapeString(s string) string

HTMLEscapeString возвращает экранированный HTML-эквивалент обычных текстовых данных s.

функция HTMLEscaper

func HTMLEscaper(args ...any) string

HTMLEscaper возвращает экранированное HTML-представление текстовой формы своих аргументов.

функция IsTrue 1.6

func IsTrue(val any) (truth, ok bool)

IsTrue сообщает, является ли значение истинным, то есть не является ли оно нулевым значением своего типа, а также имеет ли значение осмысленное логическое значение. Это определение истинности, используемое действиями if и другими подобными действиями.

функция JSEscape

func JSEscape(w io.Writer, b []byte)

JSEscape записывает в w экранированный эквивалент данных b на JavaScript.

функция JSEscapeString

func JSEscapeString(s string) string

JSEscapeString возвращает экранированный эквивалент данных s на JavaScript.

функция JSEscaper

func JSEscaper(args ...any) string

JSEscaper возвращает экранированное представление текстовой формы своих аргументов на JavaScript.

функция URLQueryEscaper

func URLQueryEscaper(args ...any) string

URLQueryEscaper возвращает экранированное значение текстового представления своих аргументов в форме, подходящей для вставки в запрос URL.

тип ExecError 1.6

ExecError — пользовательский тип ошибки, возвращаемый, когда при вычислении шаблона в Execute возникает ошибка. (Если возникает ошибка записи, возвращается фактическая ошибка; она не будет иметь тип ExecError.)

type ExecError struct {
    Name string // Name of template.
    Err  error  // Pre-formatted error.
}

функция (ExecError) Error 1.6

func (e ExecError) Error() string

функция (ExecError) Unwrap 1.13

func (e ExecError) Unwrap() error

тип FuncMap

FuncMap — это тип карты, задающей соответствие имён функциям. Каждая функция должна возвращать либо одно значение, либо два значения, второе из которых имеет тип error. В последнем случае, если при выполнении второе возвращаемое значение (ошибка) не равно nil, выполнение прекращается и Execute возвращает эту ошибку.

Ошибки, возвращаемые Execute, оборачивают исходную ошибку; вызовите errors.AsType, чтобы извлечь её.

При вызове функции во время выполнения шаблона список аргументов должен быть совместим с типами параметров функции. Функции, предназначенные для работы с аргументами произвольного типа, могут использовать параметры типа interface{} или reflect.Value. Аналогично, функции, предназначенные для возврата результата произвольного типа, могут возвращать interface{} или reflect.Value.

type FuncMap map[string]any

тип Template

Template — это представление разобранного шаблона. Поле *parse.Tree экспортируется только для использования пакетом html/template; все остальные клиенты должны считать его неэкспортируемым.

type Template struct {
    *parse.Tree
    // contains filtered or unexported fields
}

Пример

Код:

// 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.New("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)
    }
}

Вывод:

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

Пример (Block)

Код:

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.New("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)
}

Вывод:

Names:
- Gamora
- Groot
- Nebula
- Rocket
- Star-Lord
Names: Gamora, Groot, Nebula, Rocket, Star-Lord

Пример (Func)

Этот пример демонстрирует пользовательскую функцию для обработки текста шаблона. Он устанавливает функцию strings.Title и использует её, чтобы сделать текст заголовка в выводе шаблона более привлекательным.

Код:

// 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.New("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)
}

Вывод:

Input: "the go programming language"
Output 0: The Go Programming Language
Output 1: "The Go Programming Language"
Output 2: "The Go Programming Language"

Пример (Funcs)

Этот пример демонстрирует регистрацию двух пользовательских функций шаблона и замену одной из них после разбора шаблона. Замену можно использовать, например, чтобы изменить поведение клонированных шаблонов.

Код:

// Define a simple template to test the functions.
const tmpl = `{{ . | lower | repeat }}`

// Define the template funcMap with two functions.
var funcMap = template.FuncMap{
    "lower":  strings.ToLower,
    "repeat": func(s string) string { return strings.Repeat(s, 2) },
}

// Define a New template, add the funcMap using Funcs and then Parse
// the template.
parsedTmpl, err := template.New("t").Funcs(funcMap).Parse(tmpl)
if err != nil {
    log.Fatal(err)
}
if err := parsedTmpl.Execute(os.Stdout, "ABC\n"); err != nil {
    log.Fatal(err)
}

// [Funcs] must be called before a template is parsed to add
// functions to the template. [Funcs] can also be used after a
// template is parsed to overwrite template functions.
//
// Here the function identified by "repeat" is overwritten.
parsedTmpl.Funcs(template.FuncMap{
    "repeat": func(s string) string { return strings.Repeat(s, 3) },
})
if err := parsedTmpl.Execute(os.Stdout, "DEF\n"); err != nil {
    log.Fatal(err)
}

Вывод:

abc
abc
def
def
def

Пример (Glob)

Здесь показано, как загрузить набор шаблонов из каталога.

Код:

// 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.ParseGlob(pattern))

err := tmpl.Execute(os.Stdout, nil)
if err != nil {
    log.Fatalf("template execution: %s", err)
}

Вывод:

T0 invokes T1: (T1 invokes T2: (This is T2))

Пример (Helpers)

Этот пример демонстрирует один из способов совместного использования шаблонов в разных контекстах. В этом варианте мы вручную добавляем несколько шаблонов-драйверов к существующему набору шаблонов.

Код:

// 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.ParseGlob(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)
}

Вывод:

Driver 1 calls T1: (T1 invokes T2: (This is T2))
Driver 2 calls T2: (This is T2)

Пример (If)

Этот пример демонстрирует использование «if».

Код:

type book struct {
    Stars float32
    Name  string
}

tpl, err := template.New("book").Parse(`{{ if (gt .Stars 4.0) }}"{{.Name }}" is a great book.{{ else }}"{{.Name}}" is not a great book.{{ end }}`)
if err != nil {
    log.Fatalf("failed to parse template: %s", err)
}

b := &book{
    Stars: 4.9,
    Name:  "Good Night, Gopher",
}
err = tpl.Execute(os.Stdout, b)
if err != nil {
    log.Fatalf("failed to execute template: %s", err)
}

Вывод:

"Good Night, Gopher" is a great book.

Пример (Share)

Этот пример демонстрирует использование одной группы шаблонов-драйверов с разными наборами вспомогательных шаблонов.

Код:

// 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 ({{.}} version) invokes T1: ({{template `T1`}})\n"},
    // T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined
    {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "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 drivers.
drivers := template.Must(template.ParseGlob(pattern))

// We must define an implementation of the T2 template. First we clone
// the drivers, then add a definition of T2 to the template name space.

// 1. Clone the helper set to create a new name space from which to run them.
first, err := drivers.Clone()
if err != nil {
    log.Fatal("cloning helpers: ", err)
}
// 2. Define T2, version A, and parse it.
_, err = first.Parse("{{define `T2`}}T2, version A{{end}}")
if err != nil {
    log.Fatal("parsing T2: ", err)
}

// Now repeat the whole thing, using a different version of T2.
// 1. Clone the drivers.
second, err := drivers.Clone()
if err != nil {
    log.Fatal("cloning drivers: ", err)
}
// 2. Define T2, version B, and parse it.
_, err = second.Parse("{{define `T2`}}T2, version B{{end}}")
if err != nil {
    log.Fatal("parsing T2: ", err)
}

// Execute the templates in the reverse order to verify the
// first is unaffected by the second.
err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second")
if err != nil {
    log.Fatalf("second execution: %s", err)
}
err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first")
if err != nil {
    log.Fatalf("first: execution: %s", err)
}

Вывод:

T0 (second version) invokes T1: (T1 invokes T2: (T2, version B))
T0 (first version) invokes T1: (T1 invokes T2: (T2, version A))

функция Must

func Must(t *Template, err error) *Template

Must — вспомогательная функция, оборачивающая вызов функции, возвращающей (*Template, error), и вызывающая панику, если ошибка не равна nil. Она предназначена для использования при инициализации переменных, например:

var t = template.Must(template.New("name").Parse("text"))

функция New

func New(name string) *Template

New выделяет новый неопределённый шаблон с заданным именем.

функция ParseFS 1.16

func ParseFS(fsys fs.FS, patterns ...string) (*Template, error)

ParseFS подобна Template.ParseFiles или Template.ParseGlob, но читает данные из файловой системы fsys, а не из файловой системы хостовой операционной системы. Она принимает список шаблонов glob (см. path.Match). (Обратите внимание: большинство имён файлов служат шаблонами glob, совпадающими только с самими собой.)

функция ParseFiles

func ParseFiles(filenames ...string) (*Template, error)

ParseFiles создаёт новый Template и разбирает определения шаблонов из указанных файлов. Имя возвращённого шаблона будет совпадать с базовым именем первого файла, а его содержимое — с разобранным содержимым этого файла. Необходимо указать хотя бы один файл. Если возникает ошибка, разбор прекращается, а возвращаемый *Template равен nil.

При разборе нескольких файлов с одинаковым именем из разных каталогов используется последний из них. Например, ParseFiles("a/foo", "b/foo") сохраняет "b/foo" как шаблон с именем "foo", а "a/foo" становится недоступным.

функция ParseGlob

func ParseGlob(pattern string) (*Template, error)

ParseGlob создаёт новый Template и разбирает определения шаблонов из файлов, найденных по шаблону. Файлы выбираются согласно семантике filepath.Match; шаблон должен соответствовать хотя бы одному файлу. Возвращённый шаблон будет иметь имя filepath.Base и разобранное содержимое первого файла, соответствующего шаблону. ParseGlob эквивалентна вызову ParseFiles со списком файлов, найденных по шаблону.

При разборе нескольких файлов с одинаковым именем из разных каталогов используется последний из них.

функция (*Template) AddParseTree

func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error)

AddParseTree связывает дерево разбора, переданное в качестве аргумента, с шаблоном t и присваивает ему указанное имя. Если шаблон ещё не определён, это дерево становится его определением. Если шаблон уже определён и имеет такое же имя, существующее определение заменяется; в противном случае создаётся, определяется и возвращается новый шаблон.

функция (*Template) Clone

func (t *Template) Clone() (*Template, error)

Clone возвращает дубликат шаблона, включая все связанные шаблоны. Фактическое представление не копируется, но копируется пространство имён связанных шаблонов, поэтому последующие вызовы Template.Parse для копии добавят шаблоны в копию, но не в исходный шаблон. Clone можно использовать для подготовки общих шаблонов и их применения с вариантными определениями других шаблонов, добавляя варианты после создания клона.

функция (*Template) DefinedTemplates 1.5

func (t *Template) DefinedTemplates() string

DefinedTemplates возвращает строку со списком определённых шаблонов, перед которым стоит строка «; defined templates are: ». Если таких шаблонов нет, возвращается пустая строка. Используется для формирования сообщения об ошибке здесь и в html/template.

функция (*Template) Delims

func (t *Template) Delims(left, right string) *Template

Delims задаёт разделители действий указанными строками для последующих вызовов Template.Parse, Template.ParseFiles или Template.ParseGlob. Вложенные определения шаблонов наследуют эти настройки. Пустой разделитель соответствует значению по умолчанию: {{ или }}. Метод возвращает шаблон, поэтому вызовы можно объединять в цепочку.

функция (*Template) Execute

func (t *Template) Execute(wr io.Writer, data any) error

Execute применяет разобранный шаблон к указанному объекту данных и записывает результат в wr. Если при выполнении шаблона или записи результата возникает ошибка, выполнение прекращается, но часть результата уже могла быть записана в Writer. Шаблон можно безопасно выполнять параллельно, хотя при совместном использовании Writer параллельными выполнениями вывод может перемешиваться.

Если data имеет тип reflect.Value, шаблон применяется к конкретному значению, содержащемуся в reflect.Value, как и в fmt.Print.

функция (*Template) ExecuteTemplate

func (t *Template) ExecuteTemplate(wr io.Writer, name string, data any) error

ExecuteTemplate применяет связанный с t шаблон с указанным именем к заданному объекту данных и записывает результат в wr. Если при выполнении шаблона или записи результата возникает ошибка, выполнение прекращается, но часть результата уже могла быть записана в Writer. Шаблон можно безопасно выполнять параллельно, хотя при совместном использовании Writer параллельными выполнениями вывод может перемешиваться.

функция (*Template) Funcs

func (t *Template) Funcs(funcMap FuncMap) *Template

Funcs добавляет элементы переданной карты в карту функций шаблона. Все функции, используемые в шаблоне, необходимо добавить до разбора шаблона. Funcs можно вызывать несколько раз, в том числе после разбора (например, после Template.Clone), чтобы заменить функцию с тем же именем; при выполнении шаблона будет использоваться замена. Метод вызывает панику, если значение в карте не является функцией с подходящим типом результата или если имя нельзя синтаксически использовать как функцию в шаблоне. Метод возвращает шаблон, поэтому вызовы можно объединять в цепочку.

функция (*Template) Lookup

func (t *Template) Lookup(name string) *Template

Lookup возвращает связанный с t шаблон с указанным именем. Если такого шаблона нет или у него нет определения, возвращается nil.

функция (*Template) Name

func (t *Template) Name() string

Name возвращает имя шаблона.

функция (*Template) New

func (t *Template) New(name string) *Template

New выделяет новый неопределённый шаблон, связанный с указанным шаблоном и имеющий те же разделители. Связь, являющаяся транзитивной, позволяет одному шаблону вызывать другой с помощью действия {{template}}.

Поскольку связанные шаблоны используют общие базовые данные, создавать шаблоны параллельно небезопасно. После создания шаблонов их можно выполнять параллельно.

функция (*Template) Option 1.5

func (t *Template) Option(opt ...string) *Template

Option задаёт параметры шаблона. Параметры описываются строками: простой строкой или строкой вида «key=value». В строке параметра может быть не более одного знака равенства. Если строка параметра не распознана или некорректна по другой причине, Option вызывает панику.

Известные параметры:

missingkey: управляет поведением при выполнении, если карта индексируется ключом, которого в ней нет.

"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.

функция (*Template) Parse

func (t *Template) Parse(text string) (*Template, error)

Parse разбирает text как тело шаблона t. Именованные определения шаблонов (инструкции {{define ...}} или {{block ...}}) в text задают дополнительные шаблоны, связанные с t, и удаляются из определения самого t.

Шаблоны можно переопределять в последовательных вызовах Parse. Определение шаблона, тело которого состоит только из пробельных символов и комментариев, считается пустым и не заменяет существующее тело шаблона. Это позволяет использовать Parse для добавления новых определений именованных шаблонов без перезаписи тела основного шаблона.

функция (*Template) ParseFS 1.16

func (t *Template) ParseFS(fsys fs.FS, patterns ...string) (*Template, error)

ParseFS подобна Template.ParseFiles или Template.ParseGlob, но читает данные из файловой системы fsys, а не из файловой системы хостовой операционной системы. Она принимает список шаблонов glob (см. path.Match). (Обратите внимание: большинство имён файлов служат шаблонами glob, совпадающими только с самими собой.)

функция (*Template) ParseFiles

func (t *Template) ParseFiles(filenames ...string) (*Template, error)

ParseFiles разбирает указанные файлы и связывает полученные шаблоны с t. Если возникает ошибка, разбор прекращается и возвращаемый шаблон равен nil; в противном случае возвращается t. Необходимо указать хотя бы один файл. Поскольку шаблоны, создаваемые ParseFiles, получают имена по базовым именам (см. filepath.Base) файлов-аргументов, имя t обычно должно совпадать с одним из базовых имён файлов. Если это не так, выполнение t.Execute может завершиться ошибкой в зависимости от содержимого t до вызова ParseFiles. В таком случае используйте t.ExecuteTemplate для выполнения подходящего шаблона.

При разборе нескольких файлов с одинаковым именем из разных каталогов используется последний из них.

функция (*Template) ParseGlob

func (t *Template) ParseGlob(pattern string) (*Template, error)

ParseGlob разбирает определения шаблонов в файлах, найденных по шаблону, и связывает полученные шаблоны с t. Файлы выбираются согласно семантике filepath.Match; шаблон должен соответствовать хотя бы одному файлу. ParseGlob эквивалентна вызову Template.ParseFiles со списком файлов, найденных по шаблону.

При разборе нескольких файлов с одинаковым именем из разных каталогов используется последний из них.

функция (*Template) Templates

func (t *Template) Templates() []*Template

Templates возвращает срез определённых шаблонов, связанных с t.

Подкаталоги

Название Краткое описание
..
parse Пакет parse строит деревья разбора шаблонов, определённых в text/template и html/template.

© Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
http://golang.org/pkg/text/template/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API