我使用xml.UnMarshal方法来获取struct对象,但它有自己的局限性。我需要一种方法,我可以在节点内获取特定类型的所有后代,而无需指定确切的xpath。
例如,我有一个以下格式的xml数据:
<content>
<p>this is content area</p>
<animal>
<p>This id dog</p>
<dog>
<p>tommy</p>
</dog>
</animal>
<birds>
<p>this is birds</p>
<p>this is birds</p>
</birds>
<animal>
<p>this is animals</p>
</animal>
</content>
现在我想遍历上面的xml并按顺序处理每个节点及其子节点。问题是这种结构不固定,元素的顺序可能会改变。所以我需要一种方法,以便我可以像
一样遍历While(Content.nextnode())
{
switch(type of node)
{
//Process the node or traverse the child node deeper
}
}
答案 0 :(得分:23)
您可以使用递归结构和简单的walk函数,使用vanilla encoding/xml
来执行此操作:
type Node struct {
XMLName xml.Name
Content []byte `xml:",innerxml"`
Nodes []Node `xml:",any"`
}
func walk(nodes []Node, f func(Node) bool) {
for _, n := range nodes {
if f(n) {
walk(n.Nodes, f)
}
}
}
游乐场示例:http://play.golang.org/p/rv1LlxaHvK。
编辑:以下是带有attrs的版本:
type Node struct {
XMLName xml.Name
Attrs []xml.Attr `xml:"-"`
Content []byte `xml:",innerxml"`
Nodes []Node `xml:",any"`
}
func (n *Node) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
n.Attrs = start.Attr
type node Node
return d.DecodeElement((*node)(n), &start)
}
答案 1 :(得分:1)
我对如何处理通用XML DOM进行了一些搜索,你可以做的最接近的是使用decoder.Token()
或decoder.RawToken()
。
但是,如果您愿意考虑使用图书馆,我发现这个库很容易上传:https://github.com/beevik/etree
doc := etree.NewDocument()
if err := doc.ReadFromFile("bookstore.xml"); err != nil {
panic(err)
}
root := doc.SelectElement("bookstore")
fmt.Println("ROOT element:", root.Tag)
for _, book := range root.SelectElements("book") {
fmt.Println("CHILD element:", book.Tag)
if title := book.SelectElement("title"); title != nil {
lang := title.SelectAttrValue("lang", "unknown")
fmt.Printf(" TITLE: %s (%s)\n", title.Text(), lang)
}
for _, attr := range book.Attr {
fmt.Printf(" ATTR: %s=%s\n", attr.Key, attr.Value)
}
}
它以上述方式使用内置的xml解析器。
答案 2 :(得分:0)
由于你要求一个库,因为你似乎想要遍历XML树,我可以推荐XMLDom-Go,我已经在过去的一些项目中使用过它。
答案 3 :(得分:0)
xmlquery支持将XML文档解析为DOM树来遍历所有节点,例如Go的html包。
答案 4 :(得分:0)
我将使用在线工具-https://www.onlinetool.io/xmltogo/
根据给定的XML创建结构。对于给定的XML,结构将如下所示:-
type Content struct {
XMLName xml.Name `xml:"content"`
Text string `xml:",chardata"`
P string `xml:"p"`
Animal []struct {
Text string `xml:",chardata"`
P string `xml:"p"`
Dog struct {
Text string `xml:",chardata"`
P string `xml:"p"`
} `xml:"dog"`
} `xml:"animal"`
Birds struct {
Text string `xml:",chardata"`
P []string `xml:"p"`
} `xml:"birds"`
}
现在解组XML并遍历任何切片。
var content Content
err := xml.Unmarshal([]byte(data), &content)
if err != nil {
fmt.Printf("error: %v", err)
return
}
fmt.Printf("Root: %#v\n", content )