|
1 | 1 | package jsonpath
|
2 | 2 |
|
3 | 3 | import (
|
4 |
| - "encoding/json" |
5 |
| - "fmt" |
6 |
| - "strconv" |
7 |
| - "strings" |
8 |
| - |
9 |
| - "github.com/evilmonkeyinc/jsonpath/option" |
10 |
| - "github.com/evilmonkeyinc/jsonpath/script" |
11 | 4 | "github.com/evilmonkeyinc/jsonpath/script/standard"
|
12 | 5 | "github.com/evilmonkeyinc/jsonpath/token"
|
13 | 6 | )
|
14 | 7 |
|
15 | 8 | // Compile will compile the JSONPath selector
|
16 |
| -func Compile(selector string) (*Selector, error) { |
17 |
| - engine := new(standard.ScriptEngine) |
18 |
| - |
19 |
| - if selector == "$[?(@.key<3),?(@.key>6)]" { |
20 |
| - // TODO |
21 |
| - selector = "$[?(@.key<3),?(@.key>6)]" |
| 9 | +func Compile(selector string, options ...Option) (*Selector, error) { |
| 10 | + jsonPath := &Selector{ |
| 11 | + selector: selector, |
22 | 12 | }
|
23 | 13 |
|
24 |
| - jsonPath := &Selector{} |
25 |
| - if err := jsonPath.compile(selector, engine); err != nil { |
26 |
| - return nil, getInvalidJSONPathSelectorWithReason(selector, err) |
| 14 | + for _, option := range options { |
| 15 | + if err := option.Apply(jsonPath); err != nil { |
| 16 | + return nil, err |
| 17 | + } |
27 | 18 | }
|
28 | 19 |
|
29 |
| - return jsonPath, nil |
30 |
| -} |
31 |
| - |
32 |
| -// Query will return the result of the JSONPath selector applied against the specified JSON data. |
33 |
| -func Query(selector string, jsonData interface{}) (interface{}, error) { |
34 |
| - jsonPath, err := Compile(selector) |
35 |
| - if err != nil { |
36 |
| - return nil, getInvalidJSONPathSelectorWithReason(selector, err) |
| 20 | + // Set defaults if options were not used |
| 21 | + if jsonPath.engine == nil { |
| 22 | + jsonPath.engine = new(standard.ScriptEngine) |
37 | 23 | }
|
38 |
| - return jsonPath.Query(jsonData) |
39 |
| -} |
40 |
| - |
41 |
| -// QueryString will return the result of the JSONPath selector applied against the specified JSON data. |
42 |
| -func QueryString(selector string, jsonData string) (interface{}, error) { |
43 | 24 |
|
44 |
| - jsonPath, err := Compile(selector) |
| 25 | + tokenStrings, err := token.Tokenize(jsonPath.selector) |
45 | 26 | if err != nil {
|
46 | 27 | return nil, getInvalidJSONPathSelectorWithReason(selector, err)
|
47 | 28 | }
|
48 |
| - return jsonPath.QueryString(jsonData) |
49 |
| -} |
50 |
| - |
51 |
| -// Selector represents a compiled JSONPath selector |
52 |
| -// and exposes functions to query JSON data and objects. |
53 |
| -type Selector struct { |
54 |
| - Options *option.QueryOptions |
55 |
| - engine script.Engine |
56 |
| - tokens []token.Token |
57 |
| - selector string |
58 |
| -} |
59 |
| - |
60 |
| -// String returns the compiled selector string representation |
61 |
| -func (query *Selector) String() string { |
62 |
| - jsonPath := "" |
63 |
| - for _, token := range query.tokens { |
64 |
| - jsonPath += fmt.Sprintf("%s", token) |
65 |
| - } |
66 |
| - return jsonPath |
67 |
| -} |
68 |
| - |
69 |
| -func (query *Selector) compile(selector string, engine script.Engine) error { |
70 |
| - query.engine = engine |
71 |
| - query.selector = selector |
72 |
| - |
73 |
| - tokenStrings, err := token.Tokenize(selector) |
74 |
| - if err != nil { |
75 |
| - return err |
76 |
| - } |
77 | 29 |
|
78 | 30 | tokens := make([]token.Token, len(tokenStrings))
|
79 | 31 | for idx, tokenString := range tokenStrings {
|
80 |
| - token, err := token.Parse(tokenString, query.engine, query.Options) |
| 32 | + token, err := token.Parse(tokenString, jsonPath.engine, jsonPath.Options) |
81 | 33 | if err != nil {
|
82 |
| - return err |
| 34 | + return nil, getInvalidJSONPathSelectorWithReason(selector, err) |
83 | 35 | }
|
84 | 36 | tokens[idx] = token
|
85 | 37 | }
|
86 |
| - query.tokens = tokens |
| 38 | + jsonPath.tokens = tokens |
87 | 39 |
|
88 |
| - return nil |
| 40 | + return jsonPath, nil |
89 | 41 | }
|
90 | 42 |
|
91 |
| -// Query will return the result of the JSONPath query applied against the specified JSON data. |
92 |
| -func (query *Selector) Query(root interface{}) (interface{}, error) { |
93 |
| - if len(query.tokens) == 0 { |
94 |
| - return nil, getInvalidJSONPathSelector(query.selector) |
95 |
| - } |
96 |
| - |
97 |
| - tokens := make([]token.Token, 0) |
98 |
| - if len(query.tokens) > 1 { |
99 |
| - tokens = query.tokens[1:] |
100 |
| - } |
101 |
| - |
102 |
| - found, err := query.tokens[0].Apply(root, root, tokens) |
| 43 | +// Query will return the result of the JSONPath selector applied against the specified JSON data. |
| 44 | +func Query(selector string, jsonData interface{}, options ...Option) (interface{}, error) { |
| 45 | + jsonPath, err := Compile(selector, options...) |
103 | 46 | if err != nil {
|
104 |
| - return nil, err |
| 47 | + return nil, getInvalidJSONPathSelectorWithReason(selector, err) |
105 | 48 | }
|
106 |
| - return found, nil |
| 49 | + return jsonPath.Query(jsonData) |
107 | 50 | }
|
108 | 51 |
|
109 |
| -// QueryString will return the result of the JSONPath query applied against the specified JSON data. |
110 |
| -func (query *Selector) QueryString(jsonData string) (interface{}, error) { |
111 |
| - jsonData = strings.TrimSpace(jsonData) |
112 |
| - if jsonData == "" { |
113 |
| - return nil, getInvalidJSONData(errDataIsUnexpectedTypeOrNil) |
114 |
| - } |
115 |
| - |
116 |
| - var root interface{} |
117 |
| - |
118 |
| - if strings.HasPrefix(jsonData, "{") && strings.HasSuffix(jsonData, "}") { |
119 |
| - // object |
120 |
| - root = make(map[string]interface{}) |
121 |
| - if err := json.Unmarshal([]byte(jsonData), &root); err != nil { |
122 |
| - return nil, getInvalidJSONData(err) |
123 |
| - } |
124 |
| - } else if strings.HasPrefix(jsonData, "[") && strings.HasSuffix(jsonData, "]") { |
125 |
| - // array |
126 |
| - root = make([]interface{}, 0) |
127 |
| - if err := json.Unmarshal([]byte(jsonData), &root); err != nil { |
128 |
| - return nil, getInvalidJSONData(err) |
129 |
| - } |
130 |
| - } else if len(jsonData) > 2 && strings.HasPrefix(jsonData, "\"") && strings.HasPrefix(jsonData, "\"") { |
131 |
| - // string |
132 |
| - root = jsonData[1 : len(jsonData)-1] |
133 |
| - } else if strings.ToLower(jsonData) == "true" { |
134 |
| - // bool true |
135 |
| - root = true |
136 |
| - } else if strings.ToLower(jsonData) == "false" { |
137 |
| - // bool false |
138 |
| - root = false |
139 |
| - } else if val, err := strconv.ParseInt(jsonData, 10, 64); err == nil { |
140 |
| - // integer |
141 |
| - root = val |
142 |
| - } else if val, err := strconv.ParseFloat(jsonData, 64); err == nil { |
143 |
| - // float |
144 |
| - root = val |
145 |
| - } else { |
146 |
| - return nil, getInvalidJSONData(errDataIsUnexpectedTypeOrNil) |
| 52 | +// QueryString will return the result of the JSONPath selector applied against the specified JSON data. |
| 53 | +func QueryString(selector string, jsonData string, options ...Option) (interface{}, error) { |
| 54 | + jsonPath, err := Compile(selector, options...) |
| 55 | + if err != nil { |
| 56 | + return nil, getInvalidJSONPathSelectorWithReason(selector, err) |
147 | 57 | }
|
148 |
| - |
149 |
| - return query.Query(root) |
| 58 | + return jsonPath.QueryString(jsonData) |
150 | 59 | }
|
0 commit comments