在Go中使用html/template生成XML会因自动HTML转义导致
在go中使用`html/template`生成xml会因自动html转义导致`
在Go语言中,html/template包的设计目标是防御XSS攻击,因此对所有未显式标记为安全的数据执行上下文敏感的自动转义(如将 完全不适用于XML生成场景——XML解析器无法识别被双重转义的
✅ 正确方案一:切换至 text/template
text/template 不执行任何自动转义,适合生成纯文本、XML、JSON、配置文件等非HTML内容:
package main
import (
"bytes"
"fmt"
"text/template" // ← 关键:替换为 text/template
)
const tmplStr = `{{define "indexSitemap"}}<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{{range .Sitemaps}}
<sitemap>
<loc>{{.Loc}}</loc>
</sitemap>
{{end}}
</sitemapindex>{{end}}`
type SitemapEntry struct {
Loc string
}
type SitemapData struct {
Sitemaps []SitemapEntry
}
func main() {
tmpl, err := template.New("sitemap").Parse(tmplStr)
if err != nil {
panic(err)
}
data := SitemapData{
Sitemaps: []SitemapEntry{
{Loc: "https://www.test.com/sitemap.xml"},
{Loc: "https://www.test.com/events-sitemap.xml"},
{Loc: "https://www.test.com/gamesAndTeams-sitemap.xml"},
},
}
buf := new(bytes.Buffer)
if err := tmpl.ExecuteTemplate(buf, "indexSitemap", data); err != nil {
panic(err)
}
fmt.Println(buf.String()) // 输出标准、可解析的XML
}⚠️ 注意:text/template 不提供安全防护,务必确保所有动态插入的内容(如 .Loc)本身已符合XML规范(例如不含未转义的 , &, ", ')。若数据来源不可信,需手动清理或预处理。
✅ 正确方案二(推荐):使用 encoding/xml 直接序列化
更安全、更健壮的方式是放弃模板,采用结构体+XML序列化。Go标准库的 encoding/xml 天然支持XML声明、命名空间、属性与嵌套,并自动处理必需的字符转义:
立即学习“前端免费学习笔记(深入)”;
package main
import (
"encoding/xml"
"fmt"
)
type SitemapIndex struct {
XMLName xml.Name `xml:"sitemapindex"`
XMLNS string `xml:"xmlns,attr"`
Sitemaps []Sitemap `xml:"sitemap"`
}
type Sitemap struct {
Loc string `xml:"loc"`
}
func main() {
sitemap := SitemapIndex{
XMLNS: "http://www.sitemaps.org/schemas/sitemap/0.9",
Sitemaps: []Sitemap{
{Loc: "https://www.test.com/sitemap.xml"},
{Loc: "https://www.test.com/events-sitemap.xml"},
{Loc: "https://www.test.com/gamesAndTeams-sitemap.xml"},
},
}
// 生成带XML声明的字节流
output, err := xml.MarshalIndent(sitemap, "", " ")
if err != nil {
panic(err)
}
// 拼接XML声明(xml.Marshal 不包含声明)
result := []byte(`<?xml version="1.0" encoding="UTF-8"?>` + "\n" + string(output))
fmt.Println(string(result))
}✅ 优势:
- 零模板注入风险:结构体字段值由encoding/xml按XML规则安全转义;
- 强类型约束:编译期检查字段名与标签合法性;
- 可读性与可维护性更高:逻辑与数据分离,易于单元测试;
- 天然支持命名空间、CDATA、属性等高级特性。
❌ 不推荐的“绕过”方式
- 在html/template中使用template.HTML()强制标记为安全:❌ 危险!可能引入未转义的恶意字符,破坏XML结构;
- 删除XML声明中的?(如
):❌ 表面“修复”,实为掩盖问题,且不符合XML规范; - 手动字符串替换(如strings.ReplaceAll(buf.String(), "
总结
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 简单、静态、可信XML生成 | text/template | 轻量、灵活,但需自行保障内容安全 |
| 生产级、动态、多源数据XML | encoding/xml + struct | 安全、标准、可扩展、易测试 |
| HTML页面内嵌XML片段 | html/template + template.XML | 仅限明确需要HTML上下文安全的混合场景 |
始终牢记:模板引擎的选择应由输出内容类型决定,而非习惯或便利性。对XML,请坚定选择text/template或更优的encoding/xml。



















