本课程介绍设备端如何从Aligenie SDK获取/组装JSON信息。获取JSON信息以自定义语音技能的实体值为例。

JSON是什么?

JSON(JavaScript Object Notation)是一种基于文本的数据交换格式。无论你的应用是用哪种开发语言编写的(Java/EE,Ruby,PHP,C#/.Net等等),你都可以使用JSON来通过网络进行数据交互和处理。几乎所有的编程语言都有很好的库或第三方工具来提供基于JSON的API支持,因此你可以非常方便地使用任何自己喜欢的编程语言来处理JSON数据。而另一方面随着REST、像MongoDB这样的NoSQL技术或标准的广泛使用,JSON也正成为一种被推荐的数据交互格式。


作者:技匠
参考资料:https://www.jianshu.com/p/8b428e1d1564

Json解析库

在C/C++语言编程中,常使用json-c或者cJson作为json解析库。Aligenie SDK已经移植好了json-c,并已广泛应用到了各个模块中,二次开发时可以直接使用。json-c相关头文件位于component/json-c目录下。要使用json-c,最简单的方式是包含头文件#include “json-c/json.h”,json-c介绍和API使用方法可参考:https://www.jianshu.com/p/659bb1b09f1b。也可参考官方源代码自带的test用例:https://github.com/json-c/json-c/tree/master/tests

Json解析

示例代码

  1. { "slots": [ { "name": "set", "domainSlot": "set:underlying settings", "liveTime": 0, "value": "清洗机器", "norm": "000002" } ], "domain": "净饮机语音控制", "query": "清洗机器", "intent": "pass_Settings" }

如上所示,是某款可语音控制净饮机产品的私有技能控制指令,我们从中解析出norm字段(语音实体值编号),具体查看自定义技能相关指导。

  1. #include "json-c/json.h"
  2. #define PARAM_STRING "{ \"slots\": [ { \"name\": \"set\", \"domainSlot\": \"set:underlying settings\", \"liveTime\": 0, \"value\": \"清洗机器\", \"norm\": \"000002\" } ], \"domain\": \"净饮机语音控制\", \"query\": \"清洗机器\", \"intent\": \"pass_Settings\" }"
  3. void parse_norm_from_param(void)
  4. {
  5. json_object *param_json_obj = NULL;
  6. json_object *slots_json_obj = NULL;
  7. json_object *slot_json_obj = NULL;
  8. json_object *norm_json_obj = NULL;
  9. char *norm = NULL;
  10. int slots_cnt = 0;
  11. int i = 0;
  12. //将字符串转化为json object
  13. param_json_obj = json_tokener_parse(PARAM_STRING);
  14. if (!param_json_obj) {
  15. printf("parse PARAM_STRING to json format fail\n");
  16. return;
  17. }
  18. //从param json object中解析slots数组,得到slots json array object
  19. json_object_object_get_ex(param_json_obj, "slots", &slots_json_obj);
  20. if (!slots_json_obj) {
  21. printf("parse slots ftom param_json_obj fail\n");
  22. json_object_put(param_json_obj);
  23. return;
  24. }
  25. //获取slots json array object的长度,与C语言数组长度概念一致
  26. slots_cnt = json_object_array_length(slots_json_obj);
  27. //遍历slots json array object
  28. for (i = 0; i < slots_cnt; i++) {
  29. slot_json_obj = NULL;
  30. norm_json_obj = NULL;
  31. //得到每一个数组成员slot json object
  32. slot_json_obj = json_object_array_get_idx(slots_json_obj, i);
  33. if (!slot_json_obj) {
  34. printf("get slot from slots_json_obj fail\n");
  35. continue;
  36. }
  37. //从slot json object中获取解析norm,得到norm json object
  38. json_object_object_get_ex(slot_json_obj, "norm", &norm_json_obj);
  39. if (!norm_json_obj) {
  40. printf("get norm from slot_json_obj fail\n");
  41. continue;
  42. }
  43. //得到norm json objectC语言字符串格式
  44. norm = json_object_get_string(norm_json_obj);
  45. printf("slot[%d].norm:%s\n", i + 1, norm);
  46. }
  47. //param json object使用完成,销毁并释放内存,避免内存泄漏
  48. json_object_put(param_json_obj);
  49. return;
  50. }

完整的示例代码已经提交到代码工程中:component/json-c/demo.c,并封装成一个串口指令:json_demo来执行这块代码,可供参考使用。如下所示,为json_demo的演示结果:

  1. (cli-uart)# json_demo
  2. [proc_onecmd] ==> enter
  3. slot[1].norm:000002
  4. [proc_onecmd] ==> leave

注意事项

  1. 避免内存泄漏:json_tokener_parse()函数内部会申请内存,所以在json object使用完之后需要调用json_object_put()来销毁,释放内存。json_tokener_parse()和json_object_put()总是成对出现的。不规范的使用会导致内存泄漏,当内存不足时会触发panic系统死机。
  2. 避免异常数据访问:调用json_object_put()之后,所有中间其它json object以及通过json_object_get_string()得到的字符串都会被销毁,切不可再次访问,否则可能出现数据错误,严重的话会触发panic系统死机。如需使用从json object解析出的一些数据,需要在解析之后自行拷贝到其它数组或者申请一块内存进行拷贝存储。
  3. 异常处理:所有json-c库的API在调用之前都要判断传入参数是否合法,比如下面第6行的json_object_object_get_ex()中使用param_json_obj之前,会先判断其是否为空;如果为空,说明前序逻辑有异常,需要做异常处理,此处不应该再去用它。
    1. param_json_obj = json_tokener_parse(PARAM_STRING);
    2. if (!param_json_obj) {
    3. printf("parse PARAM_STRING to json format fail\n");
    4. return;
    5. }
    6. json_object_object_get_ex(param_json_obj, "slots", &slots_json_obj);

    json组装

    示例代码

    待更新。

    注意事项

    待更新。