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
Most Helpful This Week