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
|
package jsonpath
// pathNode is used to construct a trie of paths to be matched
type pathNode struct {
matchOn interface{} // string, or integer
childNodes []pathNode
action DecodeAction
}
// match climbs the trie to find a node that matches the given JSON path.
func (n *pathNode) match(path JsonPath) *pathNode {
var node *pathNode = n
for _, ps := range path {
found := false
for i, n := range node.childNodes {
if n.matchOn == ps {
node = &node.childNodes[i]
found = true
break
} else if _, ok := ps.(int); ok && n.matchOn == AnyIndex {
node = &node.childNodes[i]
found = true
break
}
}
if !found {
return nil
}
}
return node
}
// PathActions represents a collection of DecodeAction functions that should be called at certain path positions
// when scanning the JSON stream. PathActions can be created once and used many times in one or more JSON streams.
type PathActions struct {
node pathNode
}
// DecodeAction handlers are called by the Decoder when scanning objects. See PathActions.Add for more detail.
type DecodeAction func(d *Decoder) error
// Add specifies an action to call on the Decoder when the specified path is encountered.
func (je *PathActions) Add(action DecodeAction, path ...interface{}) {
var node *pathNode = &je.node
for _, ps := range path {
found := false
for i, n := range node.childNodes {
if n.matchOn == ps {
node = &node.childNodes[i]
found = true
break
}
}
if !found {
node.childNodes = append(node.childNodes, pathNode{matchOn: ps})
node = &node.childNodes[len(node.childNodes)-1]
}
}
node.action = action
}
|