Go Text Templates

Introduction

Go’s text/template package provides powerful tools for creating and executing templates. Templates allow you to generate text dynamically by combining static content with data. This is particularly useful for generating HTML, email content, configuration files, and other types of structured text. In this chapter, you will learn the basics of using text templates in Go, including defining templates, passing data to templates, and using template functions.

Basic Usage

Defining and Executing a Template

To define and execute a basic template, you create a template.Template object, define the template content, and then execute the template with data.

Example:

package main

import (
    "os"
    "text/template"
)

func main() {
    // Define a template
    tmpl := `Hello, {{.Name}}!`

    // Create a new template and parse the content
    t := template.Must(template.New("example").Parse(tmpl))

    // Define data to pass to the template
    data := struct {
        Name string
    }{
        Name: "Alice",
    }

    // Execute the template with the data and write the output to stdout
    t.Execute(os.Stdout, data)
}

In this example, a simple template is defined with a placeholder for the Name field. The template.Must function ensures that the template is parsed correctly, and t.Execute executes the template with the provided data.

Passing Data to Templates

You can pass various types of data to templates, including structs, maps, and slices.

Example: Passing a Struct

package main

import (
    "os"
    "text/template"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    tmpl := `Name: {{.Name}}, Age: {{.Age}}`
    t := template.Must(template.New("example").Parse(tmpl))

    person := Person{
        Name: "Bob",
        Age:  30,
    }

    t.Execute(os.Stdout, person)
}

In this example, a Person struct is passed to the template, which uses the Name and Age fields.

Example: Passing a Map

package main

import (
    "os"
    "text/template"
)

func main() {
    tmpl := `Name: {{.Name}}, Age: {{.Age}}`
    t := template.Must(template.New("example").Parse(tmpl))

    data := map[string]interface{}{
        "Name": "Carol",
        "Age":  25,
    }

    t.Execute(os.Stdout, data)
}

In this example, a map is passed to the template, which uses the Name and Age keys.

Control Structures

Templates support control structures like if, range, and with.

Example: If Statement

package main

import (
    "os"
    "text/template"
)

func main() {
    tmpl := `{{if .IsAdmin}}Welcome, admin!{{else}}Welcome, user!{{end}}`
    t := template.Must(template.New("example").Parse(tmpl))

    data := struct {
        IsAdmin bool
    }{
        IsAdmin: true,
    }

    t.Execute(os.Stdout, data)
}

In this example, the if statement is used to conditionally display different messages based on the IsAdmin field.

Example: Range Statement

package main

import (
    "os"
    "text/template"
)

func main() {
    tmpl := `{{range .}}Name: {{.Name}}, Age: {{.Age}}
{{end}}`
    t := template.Must(template.New("example").Parse(tmpl))

    people := []struct {
        Name string
        Age  int
    }{
        {"Dave", 40},
        {"Eve", 35},
    }

    t.Execute(os.Stdout, people)
}

In this example, the range statement is used to iterate over a slice of structs and display their fields.

Example: With Statement

package main

import (
    "os"
    "text/template"
)

func main() {
    tmpl := `{{with .Address}}City: {{.City}}, State: {{.State}}{{end}}`
    t := template.Must(template.New("example").Parse(tmpl))

    data := struct {
        Name    string
        Address struct {
            City  string
            State string
        }
    }{
        Name: "Frank",
        Address: struct {
            City  string
            State string
        }{
            City:  "New York",
            State: "NY",
        },
    }

    t.Execute(os.Stdout, data)
}

In this example, the with statement is used to simplify access to the Address field within the template.

Template Functions

You can use built-in template functions or define custom functions to extend template capabilities.

Example: Built-In Functions

package main

import (
    "os"
    "text/template"
)

func main() {
    tmpl := `{{len .Names}} names: {{join .Names ", "}}`
    funcMap := template.FuncMap{
        "join": strings.Join,
    }
    t := template.Must(template.New("example").Funcs(funcMap).Parse(tmpl))

    data := struct {
        Names []string
    }{
        Names: []string{"George", "Helen", "Ian"},
    }

    t.Execute(os.Stdout, data)
}

In this example, the built-in len function is used to get the length of a slice, and the custom join function is used to join slice elements.

Example: Custom Functions

package main

import (
    "os"
    "strings"
    "text/template"
)

func main() {
    tmpl := `{{upper .Name}}`
    funcMap := template.FuncMap{
        "upper": strings.ToUpper,
    }
    t := template.Must(template.New("example").Funcs(funcMap).Parse(tmpl))

    data := struct {
        Name string
    }{
        Name: "john",
    }

    t.Execute(os.Stdout, data)
}

In this example, a custom function upper is defined to convert a string to uppercase.

Conclusion

Go’s text/template package provides a powerful way to generate dynamic text by combining static content with data. By understanding how to define templates, pass data to templates, use control structures, and extend templates with custom functions, you can create flexible and efficient text generation systems in your Go applications.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top