--- title: Syntax weight: 13 menu: main --- Gomplate uses the syntax understood by the Go language's [`text/template`][] package. This page documents some of that syntax, but see [the language docs][`text/template`] for full details. ## The basics Templates are just regular text, with special actions delimited by `{{` and `}}` markers. Consider the following template: ``` Hello, {{ print "World" }}! ``` If you render this template, it will produce the following output: ``` Hello, World! ``` This is obviously a contrived example, and you would likely never see this in _real life_, but this conveys the basics, which is that _actions_ are delimited by `{{` and `}}`, and are replaced with their output (if any) when the template is rendered. ## Multi-line templates By default, every line containing an action will render a newline. For example, the action block below: ``` {{ range slice "Foo" "bar" "baz" }} Hello, {{ . }}! {{ end }} ``` will produce the output below: ``` Hello, Foo! Hello, bar! Hello, baz! ``` This might not be desirable. You can use [Golang template syntax](https://golang.org/pkg/text/template/#hdr-Text_and_spaces) to fix this. Leading newlines (i.e. newlines that come before the action) can be suppressed by placing a minus sign in front of the first set of delimiters (`{{`). Putting the minus sign behind the trailing set of delimiters (`}}`) will suppress the newline _after_ the action. You can do both to suppress newlines entirely on that line. Placing the minus sign within the context (i.e. inside of `{{.}}`) has no effect. Here are a few examples. ### Suppressing leading newlines ``` {{- range slice "Foo" "bar" "baz" }} Hello, {{ . }}! {{- end }} ``` will produce this: ``` Hello, Foo! Hello, bar! Hello, baz! ``` ### Suppressing trailling newlines This code: ``` {{ range slice "Foo" "bar" "baz" -}} Hello, {{ . }}! {{ end -}} ``` yields this: ``` Hello, Foo! Hello, bar! Hello, baz! ``` ### Suppressing newlines altogether This code: ``` {{- range slice "Foo" "bar" "baz" -}} Hello, {{ . }}! {{- end -}} ``` Produces: ``` Hello, Foo!Hello, bar!Hello, baz! ``` ## Variables The result of an action can be assigned to a _variable_, which is denoted by a leading `$` character, followed by an alphanumeric string. For example: ``` {{ $w := "world" }} Hello, {{ print $w }}! Goodbye, {{ print $w }}. ``` this will render as: ``` Hello, world! Goodbye, world. ``` Variables are declared with `:=`, and can be redefined with `=`: ``` {{ $w := "hello" }} {{ $w = "goodbye" }} ``` ### Variable scope A variable's scope extends to the `end` action of the control structure (`if`, `with`, or `range`) in which it is declared, or to the end of the template if there is no such control structure. In other words, if a variable is initialized inside an `if` or `else` block, it cannot be referenced outside that block. This template will error with `undefined variable "$w"` since `$w` is only declared within `if`/`else` blocks: ``` {{ if 1 }} {{ $w := "world" }} {{ else }} {{ $w := "earth" }} {{ end }} Hello, {{ print $w }}! Goodbye, {{ print $w }}. ``` One way to approach this is to declare the variable first to an empty value: ``` {{ $w := "" }} {{ if 1 }} {{ $w = "world" }} {{ else }} {{ $w = "earth" }} {{ end -}} Hello, {{ print $w }}! Goodbye, {{ print $w }}. ``` ## Indexing arrays and maps Occasionally, multi-dimensional data such as arrays (lists, slices) and maps (dictionaries) are used in templates, sometimes through the use of [data sources][]. Accessing values within these data can be done in a few ways which bear clarifying. ### Arrays Arrays are always numerically-indexed, and individual values can be accessed with the `index` function: ``` {{ index $array 0 }} ``` To visit each value, you can loop through an array with `range`: ``` {{ range $array }} do something with {{ . }}... {{ end }} ``` If you need to keep track of the index number, you can declare two variables, separated by a comma: ``` {{ range $index, $element := $array }} do something with {{ $element }}, which is number {{ $index }} {{ end }} ``` ### Maps For maps, accessing values can be done with the `.` operator. Given a map `$map` with a key `foo`, you could access it like: ``` {{ $map.foo }} ``` However, this kind of access is limited to keys which are strings and contain only characters in the set (`a`-`z`,`A`-`Z`,`_`,`1`-`9`), and which do not begin with a number. If the key doesn't conform to these rules, you can use the `index` function (like how arrays are accessed): ``` {{ index $map "foo-bar" }} ``` And, similar to arrays, you can loop through a map with the `range`: ``` {{ range $map }} The value is {{ . }} {{ end }} ``` Or if you need keys as well: ``` {{ range $key, $value := $map }} {{ $key }}'s value is: {{ $value }} {{ end }} ``` ## Functions Almost all of gomplate's utility is provided as _functions._ These are key words (like `print` in the previous examples) that perform some action. For example, the [`base64.Encode`][] function will encode some input string as a base-64 string: ``` The word is {{ base64.Encode "swordfish" }} ``` renders as: ``` The word is c3dvcmRmaXNo ``` Go's [`text/template`][] language provides a number of built-in functions, operators, and actions that can be used in templates. Here is a list of the built-in functions, but see [the documentation](https://golang.org/pkg/text/template/#hdr-Functions) for full details: - `and`, `or`, `not`: Returns boolean AND/OR/NOT of the argument(s). - `call`: Returns the result of calling a function argument. - `html`, `js`, `urlquery`: Safely escapes input for inclusion in HTML, JavaScript, and URL query strings. - `index`: Returns the referenced element of an array or map. See also [Arrays](#arrays) and [Maps](#maps). - `len`: Returns the length of the argument. - `print`, `printf`, `println`: Aliases for Go's [`fmt.Print`](https://golang.org/pkg/fmt/#Print), [`fmt.Printf`](https://golang.org/pkg/fmt/#Printf), and [`fmt.Println`](https://golang.org/pkg/fmt/#Println) functions. See the [format documentation](https://golang.org/pkg/fmt/#hdr-Printing) for details on `printf`'s format syntax. And the following comparison operators are also supported: - `eq`: Equal (`==`) - `ne`: Not-equal (`!=`) - `lt`: Less than (`<`) - `le`: Less than or equal to (`<=`) - `gt`: Greater than (`>`) - `ge`: Greater than or equal to (`>=`) There are also a few _actions_, which are used for control flow and other purposes. See [the documentation](https://golang.org/pkg/text/template/#hdr-Actions) for details on these: - `if`/`else`/`else if`: Conditional control flow. - `with`/`else`: Conditional execution with assignment. - `range`: Looping control flow. See discussion in the [Arrays](#arrays) and [Maps](#maps) sections. - `template`: Include the output of a named template. See the [Nested templates](#nested-templates) section for more details, and the [`tmpl`](../functions/tmpl) namespace for more flexible versions of `template`. - `define`: Define a named nested template. See the [Nested templates](#nested-templates) section for more details. - `block`: Shorthand for `define` followed immediately by `template`. See also gomplate's functions, defined to the left. ## The Context Go templates are always executed with a _context_. You can reference the context with the `.` (period) character, and you can set the context in a block with the `with` action. Like so: ``` $ gomplate -i '{{ with "foo" }}The context is {{ . }}{{ end }}' The context is foo ``` Templates rendered by gomplate always have a _default_ context. You can populate the default context from data sources with the [`--context`/`c`](../usage/#context-c) flag. The special context item [`.Env`](#env) is available for referencing the system's environment variables. _Note:_ The initial context (`.`) is always available as the variable `$`, so the initial context is always available, even when shadowed with `range` or `with` blocks: ``` $ echo '{"bar":"baz"}' | gomplate -c .=stdin:///in.json -i 'context is: {{ . }} {{ with "foo" }}now context is {{ . }} but the original context is still {{ $ }} {{ end }}' context is: map[bar:baz] now context is foo but the original context is still map[bar:baz] ``` ## Nested templates Gomplate supports nested templates, using Go's `template` action. These can be defined in-line with the `define` action, or external data can be used with the [`--template`/`-t`](../usage/#template-t) flag. Note that nested templates do _not_ have access to gomplate's default [context](#the-context) (though it can be explicitly provided to the `template` action). ### In-line templates To define a nested template in-line, you can use the `define` action. ``` {{ define "T1" -}} Hello {{ . }}! {{- end -}} {{ template "T1" "World" }} {{ template "T1" }} {{ template "T1" "everybody" }} ``` This renders as: ``` Hello World! Hello ! Hello everybody! ``` ### External templates To define a nested template from an external source such as a file, use the [`--template`/`-t`](../usage/#template-t) flag. _hello.t:_ ``` Hello {{ . }}! ``` ``` $ gomplate -t hello=hello.t -i '{{ template "hello" "World" }} {{ template "hello" .Env.USER }}" Hello World! Hello hairyhenderson! ``` ## `.Env` You can easily access environment variables with `.Env`, but there's a catch: if you try to reference an environment variable that doesn't exist, parsing will fail and `gomplate` will exit with an error condition. For example: ```console $ gomplate -i 'the user is {{ .Env.USER }}' the user is hairyhenderson $ gomplate -i 'this will fail: {{ .Env.BOGUS }}' this will fail: template: :1:23: executing "" at <.Env.BOGUS>: map has no entry for key "BOGUS" ``` Sometimes, this behaviour is desired; if the output is unusable without certain strings, this is a sure way to know that variables are missing! If you want different behaviour, try [`getenv`](../functions/env/#env-getenv). [`text/template`]: https://golang.org/pkg/text/template/ [`base64.Encode`]: ../functions/base64#base64-encode [data sources]: ../datasources/