Dynamic XML parser without Struct in Go
xmlquery is an XPath query package for XML document, lets you extract data or evaluate from XML documents by an XPath expression.
Installation
go get github.com/antchfx/xmlquery
Example
package main
import (
"fmt"
"strings"
"github.com/antchfx/xmlquery"
"github.com/antchfx/xpath"
)
func main() {
s := `<?xml version="1.0" encoding="UTF-8" ?>
<breakfast_menu>
<food>
<name price="10">Berry-Berry Belgian Waffles</name>
<description>Light Belgian waffles</description>
<calories>900</calories>
</food>
<food>
<name price="20">French Toast</name>
<description>Thick slices</description>
<calories>600</calories>
</food>
<food>
<name price="30">Homestyle Breakfast</name>
<description>Two eggs, bacon or sausage</description>
<calories>950</calories>
</food>
</breakfast_menu>`
doc, err := xmlquery.Parse(strings.NewReader(s))
if err != nil {
panic(err)
}
root := xmlquery.FindOne(doc, "//breakfast_menu")
if n := root.SelectElement("//food/name"); n != nil {
fmt.Printf("Name #%s\n", n.InnerText())
}
if n := root.SelectElement("//food[2]/name"); n != nil {
fmt.Printf("Name #%s\n", n.InnerText())
}
for i, n := range xmlquery.Find(doc, "//food/name/@price") {
fmt.Printf("Price #%d %s\n", i, n.InnerText())
}
for i, n := range xmlquery.Find(doc, "//food/calories") {
fmt.Printf("Calories #%d %s\n", i, n.InnerText())
}
if n := root.SelectElement("//food[2]/name"); n != nil {
fmt.Printf("Attr #%s\n", n.Attr)
}
if n := root.SelectElement("//food[2]/name"); n != nil {
fmt.Printf("Data #%s\n", n.Data)
}
node := xmlquery.FindOne(doc, "//breakfast_menu/food[2]")
if n := node.SelectElement("//description"); n != nil {
fmt.Printf("Description #%s\n", n.InnerText())
}
expr, err := xpath.Compile("sum(//breakfast_menu/food/name/@price)")
price := expr.Evaluate(xmlquery.CreateXPathNavigator(doc)).(float64)
fmt.Printf("Total price: %f\n", price)
countexpr, err := xpath.Compile("count(//breakfast_menu/food)")
count := countexpr.Evaluate(xmlquery.CreateXPathNavigator(doc))
fmt.Printf("Food Node Counts: %f\n", count)
}
Output
Name #Berry-Berry Belgian Waffles
Name #French Toast
Price #0 10
Price #1 20
Price #2 30
Calories #0 900
Calories #1 600
Calories #2 950
Attr #[{{ price} 20}]
Data #name
description #Thick slices
total price: 60.000000
Food Node Counts: 3.000000