func substringFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} {
	return func(q query, t iterator) interface{} {
		var m string
		switch typ := functionArgs(arg1).Evaluate(t).(type) {
		case string:
			m = typ
		case query:
			node := typ.Select(t)
			if node == nil {
				return ""
			}
			m = node.Value()
		}
		var start, length float64
		var ok bool
		if start, ok = functionArgs(arg2).Evaluate(t).(float64); !ok {
			panic(errors.New("substring() function first argument type must be int"))
		} else if start < 1 {
			panic(errors.New("substring() function first argument type must be >= 1"))
		}
		start--
		if arg3 != nil {
			if length, ok = functionArgs(arg3).Evaluate(t).(float64); !ok {
				panic(errors.New("substring() function second argument type must be int"))
			}
		}
		if (len(m) - int(start)) < int(length) {
			panic(errors.New("substring() function start and length argument out of range"))
		}
		if length > 0 {
			return m[int(start):int(length+start)]
		}
		return m[int(start):]
	}
}
substringFunc is XPath functions substring function returns a part of a given string.
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()
	}
}
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()
	}
}
func namespaceFunc(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 ""
			}
		}
		type namespaceURL interface {
			NamespaceURL() string
		}
		if f, ok := v.(namespaceURL); ok {
			return f.NamespaceURL()
		}
		return v.Prefix()
	}
}
func asBool(t iterator, v interface{}) bool {
	switch v := v.(type) {
	case nil:
		return false
	case *NodeIterator:
		return v.MoveNext()
	case bool:
		return v
	case float64:
		return v != 0
	case string:
		return v != ""
	case query:
		return v.Select(t) != nil
	default:
		panic(fmt.Errorf("unexpected type: %T", v))
	}
}
func asString(t iterator, v interface{}) string {
	switch v := v.(type) {
	case nil:
		return ""
	case bool:
		if v {
			return "true"
		}
		return "false"
	case float64:
		return strconv.FormatFloat(v, 'g', -1, 64)
	case string:
		return v
	case query:
		node := v.Select(t)
		if node == nil {
			return ""
		}
		return node.Value()
	default:
		panic(fmt.Errorf("unexpected type: %T", v))
	}
}
func booleanFunc(q query, t iterator) interface{} {
	v := functionArgs(q).Evaluate(t)
	return asBool(t, v)
}
func numberFunc(q query, t iterator) interface{} {
	v := functionArgs(q).Evaluate(t)
	return asNumber(t, v)
}
func stringFunc(q query, t iterator) interface{} {
	v := functionArgs(q).Evaluate(t)
	return asString(t, v)
}
func startwithFunc(arg1, arg2 query) func(query, iterator) interface{} {
	return func(q query, t iterator) interface{} {
		var (
			m, n string
			ok   bool
		)
		switch typ := functionArgs(arg1).Evaluate(t).(type) {
		case string:
			m = typ
		case query:
			node := typ.Select(t)
			if node == nil {
				return false
			}
			m = node.Value()
		default:
			panic(errors.New("starts-with() function argument type must be string"))
		}
		n, ok = functionArgs(arg2).Evaluate(t).(string)
		if !ok {
			panic(errors.New("starts-with() function argument type must be string"))
		}
		return strings.HasPrefix(m, n)
	}
}
func endwithFunc(arg1, arg2 query) func(query, iterator) interface{} {
	return func(q query, t iterator) interface{} {
		var (
			m, n string
			ok   bool
		)
		switch typ := functionArgs(arg1).Evaluate(t).(type) {
		case string:
			m = typ
		case query:
			node := typ.Select(t)
			if node == nil {
				return false
			}
			m = node.Value()
		default:
			panic(errors.New("ends-with() function argument type must be string"))
		}
		n, ok = functionArgs(arg2).Evaluate(t).(string)
		if !ok {
			panic(errors.New("ends-with() function argument type must be string"))
		}
		return strings.HasSuffix(m, n)
	}
}
func containsFunc(arg1, arg2 query) func(query, iterator) interface{} {
	return func(q query, t iterator) interface{} {
		var (
			m, n string
			ok   bool
		)
		switch typ := functionArgs(arg1).Evaluate(t).(type) {
		case string:
			m = typ
		case query:
			node := typ.Select(t)
			if node == nil {
				return false
			}
			m = node.Value()
		default:
			panic(errors.New("contains() function argument type must be string"))
		}
		n, ok = functionArgs(arg2).Evaluate(t).(string)
		if !ok {
			panic(errors.New("contains() function argument type must be string"))
		}
		return strings.Contains(m, n)
	}
}
func matchesFunc(arg1, arg2 query) func(query, iterator) interface{} {
	return func(q query, t iterator) interface{} {
		var s string
		switch typ := functionArgs(arg1).Evaluate(t).(type) {
		case string:
			s = typ
		case query:
			node := typ.Select(t)
			if node == nil {
				return ""
			}
			s = node.Value()
		}
		var pattern string
		var ok bool
		if pattern, ok = functionArgs(arg2).Evaluate(t).(string); !ok {
			panic(errors.New("matches() function second argument type must be string"))
		}
		re, err := getRegexp(pattern)
		if err != nil {
			panic(fmt.Errorf("matches() function second argument is not a valid regexp pattern, err: %s", err.Error()))
		}
		return re.MatchString(s)
	}
}
func normalizespaceFunc(q query, t iterator) interface{} {
	var m string
	switch typ := functionArgs(q).Evaluate(t).(type) {
	case string:
		m = typ
	case query:
		node := typ.Select(t)
		if node == nil {
			return ""
		}
		m = node.Value()
	}
	var b = builderPool.Get().(stringBuilder)
	b.Grow(len(m))
	runeStr := []rune(strings.TrimSpace(m))
	l := len(runeStr)
	for i := range runeStr {
		r := runeStr[i]
		isSpace := unicode.IsSpace(r)
		if !(isSpace && (i+1 < l && unicode.IsSpace(runeStr[i+1]))) {
			if isSpace {
				r = ' '
			}
			b.WriteRune(r)
		}
	}
	result := b.String()
	b.Reset()
	builderPool.Put(b)
	return result
}