summaryrefslogtreecommitdiff
path: root/vendor/github.com/mitchellh/packer/vendor/github.com/ChrisTrenkamp/goxpath/goxpath.go
blob: af2e2f141b98d770d086c83c4b62b436e3780093 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package goxpath

import (
	"encoding/xml"
	"fmt"

	"github.com/ChrisTrenkamp/goxpath/internal/execxp"
	"github.com/ChrisTrenkamp/goxpath/internal/parser"
	"github.com/ChrisTrenkamp/goxpath/tree"
)

//Opts defines namespace mappings and custom functions for XPath expressions.
type Opts struct {
	NS    map[string]string
	Funcs map[xml.Name]tree.Wrap
	Vars  map[string]tree.Result
}

//FuncOpts is a function wrapper for Opts.
type FuncOpts func(*Opts)

//XPathExec is the XPath executor, compiled from an XPath string
type XPathExec struct {
	n *parser.Node
}

//Parse parses the XPath expression, xp, returning an XPath executor.
func Parse(xp string) (XPathExec, error) {
	n, err := parser.Parse(xp)
	return XPathExec{n: n}, err
}

//MustParse is like Parse, but panics instead of returning an error.
func MustParse(xp string) XPathExec {
	ret, err := Parse(xp)
	if err != nil {
		panic(err)
	}
	return ret
}

//Exec executes the XPath expression, xp, against the tree, t, with the
//namespace mappings, ns, and returns the result as a stringer.
func (xp XPathExec) Exec(t tree.Node, opts ...FuncOpts) (tree.Result, error) {
	o := &Opts{
		NS:    make(map[string]string),
		Funcs: make(map[xml.Name]tree.Wrap),
		Vars:  make(map[string]tree.Result),
	}
	for _, i := range opts {
		i(o)
	}
	return execxp.Exec(xp.n, t, o.NS, o.Funcs, o.Vars)
}

//ExecBool is like Exec, except it will attempt to convert the result to its boolean value.
func (xp XPathExec) ExecBool(t tree.Node, opts ...FuncOpts) (bool, error) {
	res, err := xp.Exec(t, opts...)
	if err != nil {
		return false, err
	}

	b, ok := res.(tree.IsBool)
	if !ok {
		return false, fmt.Errorf("Cannot convert result to a boolean")
	}

	return bool(b.Bool()), nil
}

//ExecNum is like Exec, except it will attempt to convert the result to its number value.
func (xp XPathExec) ExecNum(t tree.Node, opts ...FuncOpts) (float64, error) {
	res, err := xp.Exec(t, opts...)
	if err != nil {
		return 0, err
	}

	n, ok := res.(tree.IsNum)
	if !ok {
		return 0, fmt.Errorf("Cannot convert result to a number")
	}

	return float64(n.Num()), nil
}

//ExecNode is like Exec, except it will attempt to return the result as a node-set.
func (xp XPathExec) ExecNode(t tree.Node, opts ...FuncOpts) (tree.NodeSet, error) {
	res, err := xp.Exec(t, opts...)
	if err != nil {
		return nil, err
	}

	n, ok := res.(tree.NodeSet)
	if !ok {
		return nil, fmt.Errorf("Cannot convert result to a node-set")
	}

	return n, nil
}

//MustExec is like Exec, but panics instead of returning an error.
func (xp XPathExec) MustExec(t tree.Node, opts ...FuncOpts) tree.Result {
	res, err := xp.Exec(t, opts...)
	if err != nil {
		panic(err)
	}
	return res
}

//ParseExec parses the XPath string, xpstr, and runs Exec.
func ParseExec(xpstr string, t tree.Node, opts ...FuncOpts) (tree.Result, error) {
	xp, err := Parse(xpstr)
	if err != nil {
		return nil, err
	}
	return xp.Exec(t, opts...)
}