Golang实现全局XML到Map或JSON的解析器
Golang实现全局XML到Map或JSON的解析器 是否存在一个全局或标准的 XML 转映射或 JSON 转换库,还是我必须为要解析的每个 XML 部分定义结构体?
目标是对任何 XML 文档或输出,将其渲染或转换为键值对的纯文本输出。
3 回复
在Go中处理任意XML到Map或JSON的转换,确实有成熟的解决方案。你可以使用encoding/xml包配合map[string]interface{}来实现通用解析,以下是两种实用方法:
方法一:使用xml.Decoder递归解析
package main
import (
"encoding/xml"
"fmt"
"strings"
)
func parseXMLToMap(decoder *xml.Decoder) (map[string]interface{}, error) {
result := make(map[string]interface{})
for {
token, err := decoder.Token()
if err != nil {
return result, err
}
switch se := token.(type) {
case xml.StartElement:
// 处理嵌套元素
nestedMap, err := parseXMLToMap(decoder)
if err != nil {
return result, err
}
// 处理重复元素(转为数组)
if existing, ok := result[se.Name.Local]; ok {
switch val := existing.(type) {
case []interface{}:
result[se.Name.Local] = append(val, nestedMap)
default:
result[se.Name.Local] = []interface{}{val, nestedMap}
}
} else {
result[se.Name.Local] = nestedMap
}
case xml.CharData:
content := strings.TrimSpace(string(se))
if content != "" {
result["#text"] = content
}
case xml.EndElement:
return result, nil
}
}
}
func XMLToMap(xmlData []byte) (map[string]interface{}, error) {
decoder := xml.NewDecoder(strings.NewReader(string(xmlData)))
return parseXMLToMap(decoder)
}
方法二:使用第三方库github.com/clbanning/mxj
这是更完整的解决方案,专门处理任意XML到Map的转换:
package main
import (
"encoding/json"
"fmt"
"github.com/clbanning/mxj"
)
func main() {
xmlData := `
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="children">
<title lang="en">Harry Potter</title>
<author>J.K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>`
// XML转Map
m, err := mxj.NewMapXml([]byte(xmlData))
if err != nil {
panic(err)
}
fmt.Printf("Map结构: %v\n", m)
// Map转JSON
jsonData, err := m.Json()
if err != nil {
panic(err)
}
fmt.Printf("JSON输出: %s\n", jsonData)
// 直接XML转JSON
jsonData2, err := mxj.XmlToJson([]byte(xmlData))
if err != nil {
panic(err)
}
fmt.Printf("直接转换JSON: %s\n", jsonData2)
// 处理属性
m, _ = mxj.NewMapXml([]byte(xmlData), true) // true表示包含属性
fmt.Printf("包含属性的Map: %v\n", m)
}
方法三:自定义通用解析器(处理属性和文本)
package main
import (
"encoding/xml"
"encoding/json"
"fmt"
"strings"
)
type Node struct {
XMLName xml.Name
Attrs []xml.Attr `xml:",any,attr"`
Content string `xml:",chardata"`
Children []*Node `xml:",any"`
}
func (n *Node) ToMap() map[string]interface{} {
result := make(map[string]interface{})
// 添加属性
if len(n.Attrs) > 0 {
attrs := make(map[string]string)
for _, attr := range n.Attrs {
attrs[attr.Name.Local] = attr.Value
}
result["-attrs"] = attrs
}
// 添加文本内容
if n.Content != "" {
result["#text"] = strings.TrimSpace(n.Content)
}
// 处理子元素
for _, child := range n.Children {
childMap := child.ToMap()
if existing, ok := result[child.XMLName.Local]; ok {
switch val := existing.(type) {
case []interface{}:
result[child.XMLName.Local] = append(val, childMap)
default:
result[child.XMLName.Local] = []interface{}{val, childMap}
}
} else {
result[child.XMLName.Local] = childMap
}
}
return result
}
func main() {
xmlStr := `
<root attr1="value1">
<item id="1">First</item>
<item id="2">Second</item>
<nested>
<child>Content</child>
</nested>
</root>`
var node Node
if err := xml.Unmarshal([]byte(xmlStr), &node); err != nil {
panic(err)
}
resultMap := node.ToMap()
// 转换为JSON
jsonData, _ := json.MarshalIndent(resultMap, "", " ")
fmt.Println(string(jsonData))
}
安装mxj库
go get github.com/clbanning/mxj
mxj库提供了最完整的解决方案,支持:
- 任意XML到Map的转换
- 属性处理
- 命名空间支持
- 重复元素自动转为数组
- 直接XML到JSON转换
对于生产环境,推荐使用mxj库,它经过了充分测试且性能良好。


