func NSSelectOne(el *etree.Element, namespace, tag string) (*etree.Element, error) {
	return NSSelectOneCtx(DefaultNSContext, el, namespace, tag)
}
NSSelectOne behaves identically to NSSelectOneCtx, but uses DefaultNSContext as the
surrounding context.
package etreeutils
import (
	"errors"
	"fmt"
	"sort"
	"github.com/beevik/etree"
)
const (
	defaultPrefix = ""
	xmlnsPrefix   = "xmlns"
	xmlPrefix     = "xml"
	XMLNamespace   = "http://www.w3.org/XML/1998/namespace"
	XMLNSNamespace = "http://www.w3.org/2000/xmlns/"
)
var (
	DefaultNSContext = NSContext{
		prefixes: map[string]string{
			defaultPrefix: XMLNamespace,
			xmlPrefix:     XMLNamespace,
			xmlnsPrefix:   XMLNSNamespace,
		},
	}
	EmptyNSContext = NSContext{}
	ErrReservedNamespace       = errors.New("disallowed declaration of reserved namespace")
	ErrInvalidDefaultNamespace = errors.New("invalid default namespace declaration")
	ErrTraversalHalted         = errors.New("traversal halted")
)
type ErrUndeclaredNSPrefix struct {
	Prefix string
}
func (e ErrUndeclaredNSPrefix) Error() string {
	return fmt.Sprintf("undeclared namespace prefix: '%s'", e.Prefix)
}
type NSContext struct {
	prefixes map[string]string
}
func (ctx NSContext) Copy() NSContext {
	prefixes := make(map[string]string, len(ctx.prefixes)+4)
	for k, v := range ctx.prefixes {
		prefixes[k] = v
	}
	return NSContext{prefixes: prefixes}
}
func (ctx NSContext) declare(prefix, namespace string) etree.Attr {
	ctx.prefixes[prefix] = namespace
	switch prefix {
	case defaultPrefix:
		return etree.Attr{
			Key:   xmlnsPrefix,
			Value: namespace,
		}
	default:
		return etree.Attr{
			Space: xmlnsPrefix,
			Key:   prefix,
			Value: namespace,
		}
	}
}
func (ctx NSContext) SubContext(el *etree.Element) (NSContext, error) {
	newCtx := ctx.Copy()
	for _, attr := range el.Attr {
		if attr.Space == xmlnsPrefix {
			if attr.Key == xmlPrefix && attr.Value != XMLNamespace {
				return ctx, ErrReservedNamespace
			}
			if attr.Key == xmlnsPrefix {
				return ctx, ErrReservedNamespace
			}
			newCtx.declare(attr.Key, attr.Value)
		} else if attr.Space == defaultPrefix && attr.Key == xmlnsPrefix {
			if attr.Value == XMLNSNamespace {
				return ctx, ErrInvalidDefaultNamespace
			}
			newCtx.declare(defaultPrefix, attr.Value)
		}
	}
	return newCtx, nil
}
func (ctx NSContext) Prefixes() map[string]string {
	prefixes := make(map[string]string, len(ctx.prefixes))
	for k, v := range ctx.prefixes {
		prefixes[k] = v
	}
	return prefixes
}
func (ctx NSContext) LookupPrefix(prefix string) (string, error) {
	if namespace, ok := ctx.prefixes[prefix]; ok {
		return namespace, nil
	}
	return "", ErrUndeclaredNSPrefix{
		Prefix: prefix,
	}
}
type NSIterHandler func(NSContext, *etree.Element) error
func NSTraverse(ctx NSContext, el *etree.Element, handle NSIterHandler) error {
	ctx, err := ctx.SubContext(el)
	if err != nil {
		return err
	}
	err = handle(ctx, el)
	if err != nil {
		return err
	}
	for _, child := range el.ChildElements() {
		err := NSTraverse(ctx, child, handle)
		if err != nil {
			return err
		}
	}
	return nil
}
func NSDetatch(ctx NSContext, el *etree.Element) (*etree.Element, error) {
	ctx, err := ctx.SubContext(el)
	if err != nil {
		return nil, err
	}
	el = el.Copy()
	attrs := make([]etree.Attr, 0, len(el.Attr))
	for _, attr := range el.Attr {
		if attr.Space == xmlnsPrefix {
			continue
		}
		if attr.Space == defaultPrefix && attr.Key == xmlnsPrefix {
			continue
		}
		attrs = append(attrs, attr)
	}
	for prefix, namespace := range ctx.prefixes {
		if prefix == xmlnsPrefix || prefix == xmlPrefix {
			continue
		}
		if prefix == defaultPrefix && namespace == XMLNamespace {
			continue
		}
		if prefix != defaultPrefix {
			attrs = append(attrs, etree.Attr{
				Space: xmlnsPrefix,
				Key:   prefix,
				Value: namespace,
			})
		} else {
			attrs = append(attrs, etree.Attr{
				Key:   xmlnsPrefix,
				Value: namespace,
			})
		}
	}
	sort.Sort(SortedAttrs(attrs))
	el.Attr = attrs
	return el, nil
}