func localNameFunc(arg query) func(query, iterator) interface{} {
	return func(q query, t iterator) interface{} {
		var v NodeNavigator
		if arg == nil {
			v = t.Current()
		} else {
			v = arg.Clone().Select(t)
			if v == nil {
				return ""
			}
		}
		return v.LocalName()
	}
}
localNameFunc is a XPath functions local-name([node-set]).
package xpath
import (
	"errors"
	"fmt"
	"math"
	"strconv"
	"strings"
	"sync"
	"unicode"
)
type stringBuilder interface {
	WriteRune(r rune) (n int, err error)
	WriteString(s string) (int, error)
	Reset()
	Grow(n int)
	String() string
}
var builderPool = sync.Pool{New: func() interface{} {
	return newStringBuilder()
}}
func predicate(q query) func(NodeNavigator) bool {
	type Predicater interface {
		Test(NodeNavigator) bool
	}
	if p, ok := q.(Predicater); ok {
		return p.Test
	}
	return func(NodeNavigator) bool { return true }
}
func positionFunc(q query, t iterator) interface{} {
	var (
		count = 1
		node  = t.Current().Copy()
	)
	test := predicate(q)
	for node.MoveToPrevious() {
		if test(node) {
			count++
		}
	}
	return float64(count)
}
func lastFunc(q query, t iterator) interface{} {
	var (
		count = 0
		node  = t.Current().Copy()
	)
	node.MoveToFirst()
	test := predicate(q)
	for {
		if test(node) {
			count++
		}
		if !node.MoveToNext() {
			break
		}
	}
	return float64(count)
}
func countFunc(q query, t iterator) interface{} {
	var count = 0
	q = functionArgs(q)
	test := predicate(q)
	switch typ := q.Evaluate(t).(type) {
	case query:
		for node := typ.Select(t); node != nil; node = typ.Select(t) {
			if test(node) {
				count++
			}
		}
	}
	return float64(count)
}
func sumFunc(q query, t iterator) interface{} {
	var sum float64
	switch typ := functionArgs(q).Evaluate(t).(type) {
	case query:
		for node := typ.Select(t); node != nil; node = typ.Select(t) {
			if v, err := strconv.ParseFloat(node.Value(), 64); err == nil {
				sum += v
			}
		}
	case float64:
		sum = typ
	case string:
		v, err := strconv.ParseFloat(typ, 64)
		if err != nil {
			panic(errors.New("sum() function argument type must be a node-set or number"))
		}
		sum = v
	}
	return sum
}
func asNumber(t iterator, o interface{}) float64 {
	switch typ := o.(type) {
	case query:
		node := typ.Select(t)
		if node == nil {
			return float64(0)
		}
		if v, err := strconv.ParseFloat(node.Value(), 64); err == nil {
			return v
		}
	case float64:
		return typ
	case string:
		v, err := strconv.ParseFloat(typ, 64)
		if err != nil {
			panic(errors.New("ceiling() function argument type must be a node-set or number"))
		}
		return v
	}
	return 0
}
func ceilingFunc(q query, t iterator) interface{} {
	val := asNumber(t, functionArgs(q).Evaluate(t))
	return math.Ceil(val)
}
func floorFunc(q query, t iterator) interface{} {
	val := asNumber(t, functionArgs(q).Evaluate(t))
	return math.Floor(val)
}
func roundFunc(q query, t iterator) interface{} {
	val := asNumber(t, functionArgs(q).Evaluate(t))
	return round(val)
}
func nameFunc(arg query) func(query, iterator) interface{} {
	return func(q query, t iterator) interface{} {
		var v NodeNavigator
		if arg == nil {
			v = t.Current()
		} else {
			v = arg.Clone().Select(t)
			if v == nil {
				return ""
			}
		}
		ns := v.Prefix()
		if ns == "" {
			return v.LocalName()
		}
		return ns + ":" + v.LocalName()
	}
}