xml.marshal仅序列化输入值,不生成完整xml文档;需手动处理根元素、声明、缩进等,结构体字段须加xml tag,切片/map需显式指定标签名,非法类型需自定义处理。

xml.Marshal 本身不生成合法 XML 文档,只序列化你传进去的值——它不会自动加 <?xml version="1.0" encoding="UTF-8"?>,也不会保证有且仅有一个根元素。直接传 []User 或 map[string]string 会 panic 或输出非法内容。
结构体字段没加 xml tag 就等于不存在
Go 的 xml 包不会默认把字段名转成 XML 标签名,哪怕字段首字母大写也一样。
- 没加
xml:"name"的导出字段会被静默忽略,xml.Marshal返回结果里根本看不到它 - 匿名字段(如嵌入的
BaseInfo)不会自动展开,必须显式加xml:",inline"才能扁平化到父级 -
XMLName xml.Name `xml:"root"`是控制根元素名的唯一可靠方式,不加的话就用结构体类型名(比如User→<user></user>)
切片和 map 必须显式指定子元素名
直接序列化 []Item 字段时,xml 包默认用字段名小写作为外层容器标签(如 Items → <items></items>),但子项标签名无法推断。
- 正确写法:
Items []Item `xml:"item"`→ 每个元素生成一个<item></item> - 要带外层容器:
Items []Item `xml:"items>item"`→ 输出<items><item>...</item></items> -
map[string]string不支持:key 必须是可排序基础类型(string、int等),map[interface{}]string会报xml: unsupported type - 空切片或
nil切片都会生成空容器(如<items></items>),omitempty对容器本身无效,只影响字段是否出现
缩进、声明、写文件得自己补全
xml.MarshalIndent 只负责缩进,不加 XML 声明;os.WriteFile 要求 []byte,不能直接传字符串。
- 加声明:拼接
xml.Header + string(data),xml.Header是常量"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - 缩进调用:
xml.MarshalIndent(v, "", " "),第二个参数是每行前缀(通常空),第三个是每级缩进符 - 写文件别用
ioutil.WriteFile(已弃用),改用os.WriteFile("out.xml", data, 0644) - 大结构体慎用一次性
Marshal:内存压力大,优先考虑xml.NewEncoder(file).Encode(v)流式写入
time.Time、自定义类型、非法 UTF-8 会直接失败
标准库不支持这些类型原生序列化,不是 bug,是明确限制。
-
time.Time字段必须实现MarshalXML方法,或提前转成string字段(如CreatedAt string `xml:"created_at"`) - 含
func、chan、unsafe.Pointer的结构体会在xml.Marshal时 panic - 字符串含
\x00或其他非法 UTF-8 字节会报invalid UTF-8;Go 1.22+ 可用strings.ToValidUTF8清理 - 字段值为
nil指针时,xml.Marshal会跳过该字段(不报错),但空接口interface{}仍需类型安全处理
xml.Marshal 的责任,而是你构造输入值和包装输出时必须亲手处理的边界。最容易被忽略的是:你以为传了个结构体就能得到文档,其实你只给了它一个节点。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











