Есть два пути: использовать пакет text/template
или использовать типизированные строки.
text/template
Пакет text/template
генерирует текст без подмен символов. Просто поменяйте в импорте html/template
на text/template
- если вы не используете что-то особенное, ничего в коде менять не придётся.
Типизированные строки
При подстановки значений шаблоны из html/template
парсятся. Результат вставки одной и той же строки зависит от того, куда именно подставляется текст. Это называется контекст.
При подстановке значений типа string
специальные символы, такие как <>
экранируются всегда.
В пакете html/template
есть специальные строковые типы, для которых подстановка реализуется особым образом. Посмотрите тип template.HTML. При подстановке внутрь тела документа или таких элементов как div
и p
строки этого типа не экранируются.
Пример https://go.dev/play/p/6_4hueOZA6k
package main
import (
"html/template"
"os"
)
func main() {
const tpl = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{.Title}}</title>
</head>
<body>
{{range .Items}}<div>{{ . }}</div>{{else}}<div><strong>no rows</strong></div>{{end}}
</body>
</html>`
t, _ := template.New("webpage").Parse(tpl)
data := struct {
Title template.HTML
Items []template.HTML
}{
Title: "<em>My page</em>",
Items: []template.HTML{
"<b>My photos</b>",
"<i>My blog</i>",
},
}
t.Execute(os.Stdout, data)
}
Результат
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><em>My page</em></title>
</head>
<body>
<div><b>My photos</b></div><div><i>My blog</i></div>
</body>
</html>
Внутри title
спецсимволы экранированы, а в div
нет.