There is some documentation, which I consider inadequate, about the template packages at http://golang.org/pkg/text/template/ and http://golang.org/pkg/html/template/ - the html sub-package having additional security features against attacks like code injection and should be the one to be used when generating content for the web. (Here, I might use either as their interfaces are the same.) It contains definitions for many of the structures and formats that are parseable by the template package. So here I shall try to only supplement that with a few examples because I do not find the available documentation clear. First though, let me try to explain a few thoughts on terminology.
will get all the files in the local directory, and the pipe it to the grep command which filters only those files that conain the letter ‘a’ in it. Of course you could further pipe this text stream to another command.
, will list only those files with both an ‘a’ and an ‘o’ in it.
In Go, every such text stream is called a pipeline and it can also be piped to other commands. In the example below we are simply printing two pipelines with constant strings. Note that these constant strings which are within
Along with certain constructs the value of the ‘dot’ gets automatically set to the current value in the pipeline. You can therefore refer to its value as
pipelines
Unix users will already be aware of ‘piping’ data. Many commands produce a textual output - a stream of text. If you type the commandls
at the prompt, you will get a list of files in the directory. This can translated as get a list of all files in the current directory, and then pipe it to the default output which in this case is the command line screen
. At the unix command line the pipe ‘|’ symbol which is the vertical line, allows you to ‘pipe’ the text stream to another command. For example, ls | grep "a"
will get all the files in the local directory, and the pipe it to the grep command which filters only those files that conain the letter ‘a’ in it. Of course you could further pipe this text stream to another command.
ls | grep "a" | grep "o"
, will list only those files with both an ‘a’ and an ‘o’ in it.
In Go, every such text stream is called a pipeline and it can also be piped to other commands. In the example below we are simply printing two pipelines with constant strings. Note that these constant strings which are within
{{ }}
is different from static text outside of braces - the static text is copied as is without changes always. The pipeline data on the other hand could be manipulated, even though in this particular example we are not doing anything.
Full program - illustrating a pipeline
package main import ( "text/template" "os" ) func main() { t := template.New("template test") t = template.Must(t.Parse("This is just static text. \n{{\"This is pipeline data - because it is evaluated within the double braces.\"}} {{`So is this, but within reverse quotes.`}}\n")); t.Execute(os.Stdout, nil) }
This is just static text.
This is pipeline data - because it is evaluated within the double braces. So is this, but within reverse quotes.
This is pipeline data - because it is evaluated within the double braces. So is this, but within reverse quotes.
template if-else-end
The syntax ofif-else
construct is similar to normal if-else statements - in Go, if the pipeline is empty, then the if condition evaluates to false. The following example illustrates the two.
Full program - illustrating template if-else
package main import ( "os" "text/template" ) func main() { tEmpty := template.New("template test") tEmpty = template.Must(tEmpty.Parse("Empty pipeline if demo: {{if ``}} Will not print. {{end}}\n")) //empty pipeline following if tEmpty.Execute(os.Stdout, nil) tWithValue := template.New("template test") tWithValue = template.Must(tWithValue.Parse("Non empty pipeline if demo: {{if `anything`}} Will print. {{end}}\n")) //non empty pipeline following if condition tWithValue.Execute(os.Stdout, nil) tIfElse := template.New("template test") tIfElse = template.Must(tIfElse.Parse("if-else demo: {{if `anything`}} Print IF part. {{else}} Print ELSE part.{{end}}\n")) //non empty pipeline following if condition tIfElse.Execute(os.Stdout, nil) }
Empty pipeline if demo:
Non empty pipeline if demo: Will print.
if-else demo: Print IF part.
Non empty pipeline if demo: Will print.
if-else demo: Print IF part.
The dot - .
The dot (.) is used in Go templates to refer to the current pipeline. This is similar to acursor
used with database access to indicate the current row that is being used among all the rows returned by a query. Or if you are used to Java and C++, you could think it is something like the this
operator - well, not really, but kinda.Along with certain constructs the value of the ‘dot’ gets automatically set to the current value in the pipeline. You can therefore refer to its value as
{{.}}
.
template with-end
The with statement sets the value of dot with the value of the pipeline. If the pipeline is empty, then whatever is between thewith-end
block is skipped.
Full program - illustrating template if-else
package main import ( "os" "text/template" ) func main() { t, _ := template.New("test").Parse("{{with `hello`}}{{.}}{{end}}!\n") t.Execute(os.Stdout, nil) t1, _ = template.New("test").Parse("{{with `hello`}}{{.}} {{with `Mary`}}{{.}}{{end}}{{end}}!\n") //when nested, the dot takes the value according to closest scope. t1.Execute(os.Stdout, nil) }
hello!
hello Mary!
hello Mary!
template variables
You can create local variables for the pipelines within the template by prefixing the variable name with a "$" sign. Variable names have to be composed of alphanumeric characters and the underscore. In the example below I have used a few variations that work for variable names.Full program - illustrating template if-else
package main import ( "os" "text/template" ) func main() { t := template.Must(template.New("name").Parse("{{with $3 := `hello`}}{{$3}}{{end}}!\n")) t.Execute(os.Stdout, nil) t1 := template.Must(template.New("name1").Parse("{{with $x3 := `hola`}}{{$x3}}{{end}}!\n")) t1.Execute(os.Stdout, nil) t2 := template.Must(template.New("name2").Parse("{{with $x_1 := `hey`}}{{$x_1}} {{.}} {{$x_1}}{{end}}!\n")) t2.Execute(os.Stdout, nil) }
hello!
hola!
hey hey hey!
hola!
hey hey hey!
Predefined template functions
There are also a few predefined template functions that you can employ within your code. I shall illustrate theprintf
function which works similar to the function fmt.Sprintf
.
Full program - illustrating template if-else
package main import ( "os" "text/template" ) func main() { t := template.New("test") t = template.Must(t.Parse("{{with $x := `hello`}}{{printf `%s %s` $x `Mary`}}{{end}}!\n")) t.Execute(os.Stdout, nil) }
hello Mary!
Thanks for your awesome tutorials.
ReplyDeleteIn the "template with-end" section, the second "=" should be ":=".