func GetAttrValOrEmpty(n Elem, local, space string) string {
	val, ok := GetAttributeVal(n, local, space)
	if !ok {
		return ""
	}
	return val
}
GetAttrValOrEmpty is like GetAttributeVal, except it returns an empty string if
the attribute is not found instead of false.
package tree
import (
	"encoding/xml"
	"sort"
)
const XMLSpace = "http://www.w3.org/XML/1998/namespace"
type NodePos int
func (n NodePos) Pos() int {
	return int(n)
}
type NodeType int
func (t NodeType) GetNodeType() NodeType {
	return t
}
const (
	NtAttr NodeType = iota
	NtChd
	NtComm
	NtElem
	NtNs
	NtRoot
	NtPi
)
type Node interface {
	ResValue() string
	Pos() int
	GetToken() xml.Token
	GetParent() Elem
	GetNodeType() NodeType
}
type Elem interface {
	Node
	GetChildren() []Node
	GetAttrs() []Node
}
type NSElem interface {
	Elem
	GetNS() map[xml.Name]string
}
type NSBuilder struct {
	NS map[xml.Name]string
}
func (ns NSBuilder) GetNS() map[xml.Name]string {
	return ns.NS
}
type nsValueSort []NS
func (ns nsValueSort) Len() int { return len(ns) }
func (ns nsValueSort) Swap(i, j int) {
	ns[i], ns[j] = ns[j], ns[i]
}
func (ns nsValueSort) Less(i, j int) bool {
	return ns[i].Value < ns[j].Value
}
func BuildNS(t Elem) (ret []NS) {
	vals := make(map[xml.Name]string)
	if nselem, ok := t.(NSElem); ok {
		buildNS(nselem, vals)
		ret = make([]NS, 0, len(vals))
		i := 1
		for k, v := range vals {
			if !(k.Local == "xmlns" && k.Space == "" && v == "") {
				ret = append(ret, NS{
					Attr:     xml.Attr{Name: k, Value: v},
					Parent:   t,
					NodeType: NtNs,
				})
				i++
			}
		}
		sort.Sort(nsValueSort(ret))
		for i := range ret {
			ret[i].NodePos = NodePos(t.Pos() + i + 1)
		}
	}
	return ret
}
func buildNS(x NSElem, ret map[xml.Name]string) {
	if x.GetNodeType() == NtRoot {
		return
	}
	if nselem, ok := x.GetParent().(NSElem); ok {
		buildNS(nselem, ret)
	}
	for k, v := range x.GetNS() {
		ret[k] = v
	}
}
type NS struct {
	xml.Attr
	Parent Elem
	NodePos
	NodeType
}
func (ns NS) GetToken() xml.Token {
	return ns.Attr
}
func (ns NS) GetParent() Elem {
	return ns.Parent
}
func (ns NS) ResValue() string {
	return ns.Attr.Value
}
func GetAttribute(n Elem, local, space string) (xml.Attr, bool) {
	attrs := n.GetAttrs()
	for _, i := range attrs {
		attr := i.GetToken().(xml.Attr)
		if local == attr.Name.Local && space == attr.Name.Space {
			return attr, true
		}
	}
	return xml.Attr{}, false
}
func GetAttributeVal(n Elem, local, space string) (string, bool) {
	attr, ok := GetAttribute(n, local, space)
	return attr.Value, ok
}