|
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