Go中生成XML文件需用encoding/xml包:先定义导出结构体并添加xml标签,再用xml.Marshal或xml.MarshalIndent序列化为字节流,最后通过os.WriteFile写入文件;大文件推荐xml.NewEncoder流式写入以避免内存溢出。

用 xml.Marshal 生成 XML 字节流,再写入文件
Go 标准库的 encoding/xml 不直接提供“写文件”函数,核心是先序列化为 []byte 或流式写入 io.Writer。最常用、最稳妥的方式是:定义结构体 → 用 xml.Marshal 得到字节 → 用 os.WriteFile(或 os.Create + Write)落地。
注意结构体字段必须导出(首字母大写),且需用 xml tag 显式控制命名和行为:
type Person struct {
XMLName xml.Name `xml:"person"`
Name string `xml:"name"`
Age int `xml:"age"`
City string `xml:"city,omitempty"` // omitempty 表示空值不输出该字段
}
常见错误:忘记加 XMLName 字段导致根元素名不对;字段小写没导出,结果 XML 是空的;omitempty 误用于非零值字段(如 int 类型的 0 会被跳过)。
用 xml.Encoder 流式写入,适合大文件或避免内存堆积
当 XML 数据较大(比如导出上万条记录),xml.Marshal 会一次性把全部内容加载进内存,容易 OOM。xml.Encoder 可以边编码边写入文件,内存占用稳定。
立即学习“go语言免费学习笔记(深入)”;
关键步骤:
- 用
os.Create打开文件,得到*os.File(实现了io.Writer) - 用
xml.NewEncoder包装它 - 调用
Encode方法逐个写入结构体(注意:每个Encode都会输出完整 XML 文档头和根节点,所以通常只调用一次) - 手动写入 XML 声明(
<?xml version="1.0" encoding="UTF-8"?>)更可控
示例片段:
f, _ := os.Create("output.xml")
defer f.Close()
enc := xml.NewEncoder(f)
enc.Indent("", " ") // 启用缩进,可选
// 手动写 XML 声明
f.WriteString(`<?xml version="1.0" encoding="UTF-8"?>` + "\n")
err := enc.Encode(person) // person 是单个结构体实例
if err != nil {
log.Fatal(err)
}
处理特殊字符和 CDATA:别依赖自动转义,必要时手动包裹
xml.Marshal 和 xml.Encoder 默认会对 <、>、& 等做实体转义,这是安全的。但如果你需要保留原始 HTML 片段或脚本内容,得用 CDATA。
标准库不原生支持 CDATA,常见做法是:把字段类型设为 string,并在序列化前手动拼接 字符串,同时在 tag 中加 chardata 指令:
type Article struct {
Title string `xml:"title"`
Body string `xml:",chardata"` // 注意:这个字段必须是结构体最后一个,且不能有名字
}
然后赋值时传入:article.Body = "Hello & world
xml 包会把它当普通文本再转义一次,变成双重编码。
中文乱码?检查 encoding 声明和实际字节编码是否一致
Go 的 string 和 []byte 天然是 UTF-8,只要文件保存为 UTF-8(现代编辑器默认),XML 声明写成 <?xml version="1.0" encoding="UTF-8"?> 就能正确显示中文。
容易踩的坑:
- 用
xml.MarshalIndent时忘了在结果前手动加 XML 声明,某些解析器会按系统默认编码(如 GBK)尝试解析,报错或乱码 - Windows 下用记事本另存为 UTF-8,实际生成的是 UTF-8 with BOM,而 Go 写出的纯 UTF-8 没 BOM,部分老工具会识别失败
- 结构体字段是
[]byte类型时,如果内容本身不是 UTF-8 编码(比如 GBK 字节数组),XML 序列化后仍是非法 UTF-8,解析必然失败
真正要兼容非 UTF-8 场景,得先转码(用 golang.org/x/text/encoding),而不是改 XML 声明。


















