
go 标准库 `encoding/xml` 在解析包含同名但不同命名空间(特别是默认命名空间)的 xml 元素时,存在固有挑战,如 `` 和 `
我们的目标是能够从
理想的 Go 结构与解码冲突
直观上,我们可能会尝试使用如下的 Go 结构体来解析上述 XML:
package main
import (
"encoding/xml"
"fmt"
)
type Rss struct {
XMLName xml.Name `xml:"rss"`
Items []Item `xml:"channel>item"`
}
type Item struct {
Link string `xml:"link"` // 期望匹配 <link>
AtomLink AtomLink `xml:"https://www.php.cn/link/b2fdb4e6edcd80ed0c1620ddf6ff5389 link"` // 期望匹配 <atom:link>
}
type AtomLink struct {
Href string `xml:"href,attr"`
}
func main() {
xmlData := `
<rss version="2.0">
<channel>
<item>
<link>http://stackoverflow.com/rss</link>
<atom:link xmlns:atom="https://www.php.cn/link/b2fdb4e6edcd80ed0c1620ddf6ff5389" href="https://www.php.cn/link/7d08c3cfc1bc6c0ca31c8fa6d89aa0f1"/>
<description>Item description</description>
</item>
</channel>
</rss>`
var rss Rss
err := xml.Unmarshal([]byte(xmlData), &rss)
if err != nil {
fmt.Println("Unmarshal error:", err)
return
}
if len(rss.Items) > 0 {
fmt.Printf("Item Link: %s\n", rss.Items[0].Link)
fmt.Printf("Item AtomLink Href: %s\n", rss.Items[0].AtomLink.Href)
}
}登录后复制
然而,尝试运行上述代码会导致一个冲突错误:
Unmarshal error: main.Item field "Link" with tag "link" conflicts with field "AtomLink" with tag "https://www.php.cn/link/b2fdb4e6edcd80ed0c1620ddf6ff5389 link"
登录后复制

这个错误表明 encoding/xml 包无法区分 Item 结构体中的 Link 字段(标签为 link)和 AtomLink 字段(标签为 https://www.php.cn/link/b2fdb4e6edcd80ed0c1620ddf6ff5389 link),因为它们在 Go 的内部处理中被视为冲突的。尽管我们通过命名空间 URL 明确指定了 AtomLink,但对于 encoding/xml 而言,当存在同名元素时,它倾向于避免这种潜在的歧义。
默认命名空间解析的陷阱
更进一步,即使我们选择只解析其中一个,例如只保留 Link 字段而注释掉 AtomLink 字段:
type Item struct {
Link string `xml:"link"` // 期望匹配 <link>
// AtomLink AtomLink `xml:"https://www.php.cn/link/b2fdb4e6edcd80ed0c1620ddf6ff5389 link"`
}登录后复制
在这种情况下,xml:"link" 标签并不会像我们直觉认为的那样,只匹配无命名空间的 元素。相反,它会匹配任何命名空间下的 元素。如果 XML 中存在
解决方案与变通方法
鉴于 encoding/xml 的这些特性,我们需要采用一些变通方案来成功解析此类 XML。
还木有评论哦,快来抢沙发吧~