Try it yourself with our free Html Beautifier tool — runs entirely in your browser, no signup needed.

How to Format HTML in Go

How to Format HTML in Go

Formatting HTML in Go is an essential task for any web developer. When working with HTML templates or parsing HTML documents, having a well-structured and formatted HTML output is crucial for readability, maintainability, and even SEO. In this guide, we will explore how to format HTML in Go using the html/template package and the golang.org/x/net/html package.

Quick Example

Here is a minimal example that formats an HTML string using the html/template package:

package main

import (
	"bytes"
	"fmt"
	"text/template"
)

func main() {
	html := `<html><body><h1>Hello World!</h1></body></html>`
	tmpl, err := template.New("html").Parse(html)
	if err != nil {
		fmt.Println(err)
		return
	}
	buf := new(bytes.Buffer)
	err = tmpl.Execute(buf, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(buf.String())
}

This code creates a new template.Template instance, parses the HTML string, and executes the template with an empty data map. The resulting formatted HTML is then printed to the console.

Step-by-Step Breakdown

Let's walk through the code line by line:

  • html :=

    Hello World!

    `: This is the input HTML string.
  • tmpl, err := template.New("html").Parse(html): We create a new template.Template instance named "html" and parse the input HTML string. The Parse method returns a *template.Template instance and an error.
  • if err != nil { ... }: We check if there was an error during parsing. If so, we print the error and exit.
  • buf := new(bytes.Buffer): We create a new bytes.Buffer instance to store the formatted HTML output.
  • err = tmpl.Execute(buf, nil): We execute the template with an empty data map (nil). The resulting HTML is written to the buf buffer.
  • if err != nil { ... }: We check if there was an error during execution. If so, we print the error and exit.
  • fmt.Println(buf.String()): We print the formatted HTML output to the console.

Handling Edge Cases

Here are a few common edge cases to consider:

Empty/Null Input

If the input HTML string is empty or null, the Parse method will return an error.

html := ""
tmpl, err := template.New("html").Parse(html)
if err != nil {
	fmt.Println(err) // output: template: html:1:0: parse error: unexpected EOF
}

To handle this case, you can add a simple check before parsing the input HTML:

if html == "" {
	fmt.Println("Input HTML is empty")
	return
}

Invalid Input

If the input HTML string is invalid (e.g., contains syntax errors), the Parse method will return an error.

html := "<html><body><h1>Hello World!</h1></body>"
tmpl, err := template.New("html").Parse(html)
if err != nil {
	fmt.Println(err) // output: template: html:1:0: parse error: unexpected EOF
}

To handle this case, you can add a simple check before parsing the input HTML:

if !strings.HasPrefix(html, "<html>") {
	fmt.Println("Input HTML is invalid")
	return
}

Large Input

If the input HTML string is very large, the Parse method may take a long time to execute or even run out of memory. To handle this case, you can use a streaming parser like golang.org/x/net/html.

import (
	"golang.org/x/net/html"
)

func parseLargeHTML(html string) {
	t := html.NewTokenizer(strings.NewReader(html))
	for {
		tt := t.Next()
		if tt == html.ErrorToken {
			break
		}
		// process token
	}
}

Unicode/Special Characters

If the input HTML string contains Unicode or special characters, the Parse method may return an error or produce incorrect output. To handle this case, you can use a library like golang.org/x/text/unicode to normalize the input HTML string.

import (
	"golang.org/x/text/unicode/norm"
)

func normalizeHTML(html string) string {
	return norm.NFD.String(html)
}

Common Mistakes

Here are a few common mistakes developers make when formatting HTML in Go:

Mistake 1: Not checking for errors

tmpl, _ := template.New("html").Parse(html)

Corrected code:

tmpl, err := template.New("html").Parse(html)
if err != nil {
	fmt.Println(err)
	return
}

Mistake 2: Not handling empty input

html := ""
tmpl, err := template.New("html").Parse(html)

Corrected code:

if html == "" {
	fmt.Println("Input HTML is empty")
	return
}
tmpl, err := template.New("html").Parse(html)

Mistake 3: Not using a streaming parser for large input

tmpl, err := template.New("html").Parse(largeHTML)

Corrected code:

import (
	"golang.org/x/net/html"
)

func parseLargeHTML(html string) {
	t := html.NewTokenizer(strings.NewReader(html))
	for {
		tt := t.Next()
		if tt == html.ErrorToken {
			break
		}
		// process token
	}
}

Performance Tips

Here are a few performance tips for formatting HTML in Go:

Tip 1: Use a streaming parser for large input

Using a streaming parser like golang.org/x/net/html can significantly improve performance when parsing large HTML input.

Tip 2: Use a buffer to store output

Using a bytes.Buffer to store the formatted HTML output can reduce memory allocations and improve performance.

Tip 3: Avoid unnecessary parsing

Avoid parsing the same HTML input multiple times. Instead, parse the input once and store the resulting template.Template instance for future use.

FAQ

Q: What is the best way to format HTML in Go?

A: The best way to format HTML in Go is to use the html/template package and the golang.org/x/net/html package.

Q: How do I handle empty input?

A: You can add a simple check before parsing the input HTML to handle empty input.

Q: How do I handle large input?

A: You can use a streaming parser like golang.org/x/net/html to handle large input.

Q: How do I handle Unicode/special characters?

A: You can use a library like golang.org/x/text/unicode to normalize the input HTML string.

Q: What are some common mistakes developers make when formatting HTML in Go?

A: Some common mistakes include not checking for errors, not handling empty input, and not using a streaming parser for large input.

AI agent tools available. The CodeTidy MCP Server gives Claude, Cursor, and other AI agents access to 60+ developer tools. One command: npx @codetidy/mcp