如何在Golang中遍历XML数据?

时间:2015-05-15 10:06:33

标签: xml go

我使用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
   }
}

5 个答案:

答案 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)
}

游乐场:https://play.golang.org/p/d9BkGclp-1

答案 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 )

The Go Playground