1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5
6 #include "aos/list.h"
7 #include "aos/kernel.h"
8 // #include "aos/osal_debug.h" //calon
9 #include "cJSON.h"
10
11 #define TAG "cjpath"
12
13 /*
14 $.data[?(@.service=="musicX")].intent.sematic[?(@.intent=="PLAY")].slots[?(@.name=="artist" | @.name=="song")].value
15 artist + name
16
17
18 $.data[?(@.service=="musicX")].intent.sematic[?(@.intent=="RANDOM_SEARCH")]
19
20
21 $.data[?(@.service=="musicX")].intent.sematic[?(@.intent=="INSTRUCTION")].slots[@.name=="insType"].value
22 volulme_plus
23 volulme_minus
24 mute
25 replay
26 pause
27 close
28
29 volume_select
30 $.data[?(@.service=="musicX")].intent.sematic[?(@.intent=="INSTRUCTION")].slots[@.name=="percent" | @.name=="series"].value
31
32
33 $.data[?(@.service=="musicX")].intent.sematic[?(@.intent=="INSTRUCTION")].slots[@.name=="insType"].value
34
35 $.data[?(@.service=="cmd")].intent.sematic[?(@.intent=="SET")].slots[@.name=="series"].value
36
37 --------
38 $ 根节点开始
39 . 节点分割
40 [] 子节点操作
41 ?节点查询条件开始?()
42 @当前元素
43 ---------
44 状态
45 1. 等待根节点$
46 2.
47 */
48 typedef enum _cjpath_char_type_ {
49 CJPATH_CHAR_TYPE_NONE,
50 CJPATH_CHAR_TYPE_NORMAL,
51 CJPATH_CHAR_TYPE_KEY, /* 关键字 */
52 CJPATH_CHAR_TYPE_OPT /* 操作符 */
53 } cjpath_char_type_t;
54
55 typedef struct _lexnode {
56 slist_t next;
57 char * path;
58 char * query;
59 char * query_key;
60 char * query_value;
61 char * query_opt;
62 } lexnode_t;
63
is_space(char ch)64 static int is_space(char ch)
65 {
66 return ch == ' ';
67 }
68
69 #if 0
70 static int is_json_value_char(char ch)
71 {
72 return isalnum(ch); //TODO: utf8 support
73 }
74 #endif
75
is_opt_char(char ch)76 static int is_opt_char(char ch)
77 {
78 switch (ch) {
79 case '<':
80 case '>':
81 case '=':
82 case '!':
83 return 1;
84 break;
85 default:;
86 }
87 return 0;
88 }
89
is_key_char(char ch)90 static int is_key_char(char ch)
91 {
92 switch (ch) {
93 case '$':
94 case '[':
95 case ']':
96 case '?':
97 case '(':
98 case ')':
99 case '@':
100 case '.':
101 case '\0':
102 return 1;
103 break;
104 default:;
105 }
106
107 return 0;
108 }
109
is_json_char(char ch)110 static int is_json_char(char ch)
111 {
112 return isalnum(ch) || ch == '"' || is_space(ch) || is_key_char(ch) || is_opt_char(ch);
113 }
114
get_char_type(char ch)115 static cjpath_char_type_t get_char_type(char ch)
116 {
117 if (is_key_char(ch)) {
118 return CJPATH_CHAR_TYPE_KEY;
119 } else if (is_opt_char(ch)) {
120 return CJPATH_CHAR_TYPE_OPT;
121 } else if (isalnum(ch) || ch == '"') {
122 return CJPATH_CHAR_TYPE_NORMAL;
123 }
124 return CJPATH_CHAR_TYPE_NONE;
125 }
126
str_dup(const char * wordbegin,int wordlen)127 static char *str_dup(const char *wordbegin, int wordlen)
128 {
129 char *str = aos_zalloc(wordlen);
130 memcpy(str, wordbegin, wordlen);
131 str[wordlen] = '\0';
132 return str;
133 }
134
free_lexnode(lexnode_t * node)135 static void free_lexnode(lexnode_t *node)
136 {
137 if(node) {
138 aos_free(node->path);
139 aos_free(node->query);
140 aos_free(node->query_key);
141 aos_free(node->query_opt);
142 aos_free(node->query_value);
143 aos_free(node);
144 }
145 }
146
free_lexnode_list(slist_t * lex_list)147 static void free_lexnode_list(slist_t *lex_list)
148 {
149 lexnode_t *node;
150 slist_t * tmp;
151
152 slist_for_each_entry_safe(lex_list, tmp, node, lexnode_t, next)
153 {
154 slist_del(&node->next, lex_list);
155 free_lexnode(node);
156 }
157 }
158
159 /*
160 返回当前解析位置
161 */
get_next_word(const char * exp_str,const char ** wordbegin,int * wordlen)162 static const char *get_next_word(const char *exp_str, const char **wordbegin, int *wordlen)
163 {
164 const char * ch = exp_str;
165 int wlen = 0;
166 cjpath_char_type_t pre_char_type = CJPATH_CHAR_TYPE_NONE;
167 cjpath_char_type_t char_type = CJPATH_CHAR_TYPE_NONE;
168
169 if (exp_str == NULL || exp_str[0] == '\0') {
170 *wordbegin = NULL;
171 *wordlen = 0;
172 return NULL;
173 }
174
175 /* 去掉头部空格 */
176 while (is_space(*ch)) {
177 ch++;
178 }
179 #if 1
180 /* 引号开头的字符串处理 */
181 if(*ch == '"') {
182 *wordbegin = ch;
183 ch++;
184 for (;; ch++) {
185 wlen++;
186 if (*ch == '"') {
187 *wordlen = wlen + 1;
188 return ++ch;
189 } else if (*ch == '\0') {
190 *wordlen = wlen;
191 return ch;
192 }
193 }
194 }
195 #endif
196
197 pre_char_type = get_char_type(*ch);
198
199 *wordbegin = ch;
200 wlen = 0;
201 for (;; ch++) {
202 wlen++;
203
204 if (!is_json_char(*ch)) {
205 /* 包含无效字符 */
206 *wordbegin = NULL;
207 *wordlen = 0;
208 return NULL;
209 }
210
211 char_type = get_char_type(*ch);
212
213 /* 查到到关键字跳出, 对于一般的word关键字作为断句的依据 */
214 if (is_key_char(*ch)) {
215 break;
216 }
217
218 /* 普通字段和操作符字段切换的断句 */
219 if (pre_char_type != char_type) {
220 pre_char_type = char_type;
221 break;
222 }
223
224 pre_char_type = char_type;
225 }
226
227 /* 当前word就是关键字,解析位置向下移动 */
228 if (wlen == 1) {
229 *wordlen = wlen;
230 return ++ch;
231 }
232
233 /* 去掉尾部空格 */
234 const char *word = ch - 1;
235 wlen--;
236 while (word > exp_str && is_space(*word)) {
237 wlen--;
238 word--;
239 }
240
241 *wordlen = wlen;
242 return ch;
243 }
244
lex_process(const char * jpath,slist_t * lex_list)245 static int lex_process(const char *jpath, slist_t *lex_list)
246 {
247 char * sub_opt_status = "[?(@*=*)]";
248 int sub_opt_status_idx = -1;
249 lexnode_t *cur_node = NULL;
250 const char *wordbegin;
251 int wordlen;
252 const char *cur_pos = jpath;
253 int ret = 0;
254
255 do {
256 cur_pos = get_next_word(cur_pos, &wordbegin, &wordlen);
257 if (wordbegin == NULL || wordlen <= 0) {
258 break;
259 }
260
261 if (*wordbegin == '.') {
262 continue;
263 }
264
265 if (sub_opt_status_idx >= 0) {
266 /* 查询操作解析 */
267 if ((sub_opt_status[sub_opt_status_idx + 1] == *wordbegin) ||
268 (sub_opt_status[sub_opt_status_idx + 1] == '*') ||
269 (sub_opt_status[sub_opt_status_idx + 1] == '=' && is_opt_char(*wordbegin))) {
270 sub_opt_status_idx++;
271 } else if (sub_opt_status_idx == 0) {
272 if (isdigit(*wordbegin)) {
273 sub_opt_status_idx = strlen(sub_opt_status) - 1;
274 cur_node = aos_zalloc(sizeof(lexnode_t));
275 cur_node->query = str_dup(wordbegin, wordlen);
276 slist_add_tail(&cur_node->next, lex_list);
277 cur_node = NULL;
278 } else {
279 ret = -1;
280 break;
281 }
282 } else {
283 ret = -1;
284 break;
285 }
286
287 switch (sub_opt_status_idx) {
288 case 1: //query
289 cur_node = aos_zalloc(sizeof(lexnode_t));
290 cur_node->query = str_dup(wordbegin, wordlen);
291 break;
292 case 2:
293 case 3:
294 break;
295 case 4: //key
296 cur_node->query_key = str_dup(wordbegin, wordlen);
297 break;
298 case 5:
299 cur_node->query_opt = str_dup(wordbegin, wordlen);
300 break;
301 case 6: //value
302 if (*wordbegin)
303 cur_node->query_value = str_dup(wordbegin, wordlen);
304 break;
305 case 7:
306 slist_add_tail(&cur_node->next, lex_list);
307 cur_node = NULL;
308 break;
309 case 8:
310 sub_opt_status_idx = -1;
311 break;
312 default:
313 free_lexnode(cur_node);
314 cur_node = NULL;
315 ret = -1;
316 }
317 } else {
318 /* 路径状态解析 */
319 switch (*wordbegin) {
320 case '[':
321 /* 准备进入查询操作 */
322 sub_opt_status_idx = 0;
323 break;
324 default: {
325 cur_node = aos_zalloc(sizeof(lexnode_t));
326 cur_node->path = str_dup(wordbegin, wordlen);
327 slist_add_tail(&cur_node->next, lex_list);
328 cur_node = NULL;
329 }
330 }
331 }
332
333 } while (cur_pos && cur_pos[0] && ret == 0);
334
335 if (ret < 0) {
336 free_lexnode_list(lex_list);
337 }
338
339 return ret;
340 }
341
342 #if 0
343 static void lex_debug(const char *jpath)
344 {
345 const char *wordbegin;
346 int wordlen;
347
348 const char *cur_pos = jpath;
349
350 //int ret = 0;
351 //cJSON *cur_js = NULL;
352
353 do {
354 cur_pos = get_next_word(cur_pos, &wordbegin, &wordlen);
355 if (wordbegin == NULL) {
356 break;
357 }
358 /* debug */
359 if (wordbegin) {
360 char *ch = malloc(wordlen + 1);
361 memcpy(ch, wordbegin, wordlen);
362 ch[wordlen] = '\0';
363
364 printf("<%s>\n", ch);
365 free(ch);
366
367 } else {
368 printf("end\n");
369 break;
370 }
371 } while (cur_pos && cur_pos[0]);
372 }
373 #endif
374
cJSON_Path(cJSON * jsroot,const char * jpath)375 cJSON *cJSON_Path(cJSON *jsroot, const char *jpath)
376 {
377 /* lex debug */
378 //lex_debug(jpath);
379
380 slist_t lex_list = {NULL};
381
382 lex_process(jpath, &lex_list);
383
384 cJSON *jsquery = NULL;
385
386 lexnode_t *node;
387 slist_for_each_entry(&lex_list, node, lexnode_t, next)
388 {
389 /* lex list debug */
390 printf("%16s,%16s,%16s,%16s,%16s\n", node->path, node->query, node->query_key,
391 node->query_opt, node->query_value);
392 /*
393 查询目前支持的几种状态
394 path query key opt value
395 ----------------------------------------
396 1. $ null null null null
397 2. xxx null null null null
398 3. null 1 null null null xxx[1]
399 4. null ? name == "insType" xxx[?(name=="insType"))]
400 */
401
402 if (node->path != NULL) {
403 if (strcmp(node->path, "$") == 0) {
404 jsquery = jsroot;
405 } else if (node->path[0] != ']') {
406 jsquery = cJSON_GetObjectItem(jsquery, node->path);
407 if (jsquery == NULL) {
408 break;
409 }
410 }
411 } else if (node->query != NULL) {
412 if (cJSON_IsArray(jsquery)) {
413 if (strcmp(node->query, "?") == 0) {
414 /*子对象查找*/
415 int arr_size = cJSON_GetArraySize(jsquery);
416 int bfound = 0;
417 for (int i = 0; i < arr_size; i++) {
418 cJSON *obj = cJSON_GetArrayItem(jsquery, i);
419 cJSON *qval = cJSON_GetObjectItem(obj, node->query_key);
420 if (cJSON_IsString(qval)) {
421 int slen = strlen(node->query_value);
422 if (slen > 2 && node->query_value[0] == '"') {
423 if (strncmp(qval->valuestring, &node->query_value[1], slen - 2) ==
424 0) {
425 bfound = 1;
426 jsquery = obj;
427 break;
428 }
429 }
430 }
431 }
432
433 if (!bfound) {
434 jsquery = NULL;
435 }
436 } else {
437 /*索引下标*/
438 jsquery = cJSON_GetArrayItem(jsquery, atoi(node->query));
439 }
440 }
441 } /* query */
442 } /* for each */
443
444 return jsquery;
445 }
446