object库,提供运行时对象支持,通过引用计数维护所有对象。只要是继承自tb_object_t的对象类型都是可以经过扩展实现序列化和反序列化。

    库内部也已经提供了常用的对象类型:

    1. tb_object_data_t: 数据对象类型
    2. tb_object_date_t: 日期对象类型
    3. tb_object_null_t: 空值对象类型
    4. tb_object_array_t: 数组对象类型
    5. tb_object_string_t: 字符串对象类型
    6. tb_object_number_t: 数值对象类型,包括浮点、整型
    7. tb_object_boolean_t: 布尔对象类型
    8. tb_object_dictionary_t: 字典对象类型

    可以看到,基本上这些对象已经可以进行常用数据维护了,和apple的CoreFoundation内部的常用对象很类似,而且可以很方便的扩展其他自定义类型的序列化,这部分等以后再细讲吧。。。

    现在先简单看下如何快速解析一个json文件到内存:

    1. // 从文件读取json数据到内存,json_root为整个根对象
    2. tb_object_ref_t json_root = tb_object_read_from_url("/home/file/json.txt");
    3.  
    4. // 从http读取json数据到内存,json_root为整个根对象
    5. // tb_object_ref_t json_root = tb_object_read_from_url("http://localhost/file/json.txt");
    6.  
    7. // 从数据读取json数据到内存,json_root为整个根对象
    8. // tb_object_ref_t json_root = tb_object_read_from_data(data, size);
    9.  
    10. // 从stream读取json数据到内存,json_root为整个根对象
    11. // tb_object_ref_t json_root = tb_object_read(stream);
    12.  
    13. if (json_root)
    14. {
    15. // 将json_root的所有数据格式打印到终端,一般调试使用
    16. tb_object_dump(json_root);
    17.  
    18. // 释放json_root对象,object跟CoreFoundation一样是有引用计数的
    19. // 这里json_root没有被其他引用,所以会被立马释放掉
    20. tb_object_exit(json_root);
    21. }

    怎么样简单吧,如果要解析plist文件, 也是类似,只需换成plist 文件的url就行了 库内部回去自动检测文件格式,进行相应地解析工作,上层都是通用的object对象树 并且可以支持xplist(xml格式)、bplist(二进制格式)两种格式。

    tb_object_ref_t plist_root = tb_object_read_from_url("/home/file/file.plist");

    对于序列化到文件,也很简单:

    1. // 序列化json object到文件, size 为实际序列化的字节数,如果失败,返回:-1
    2. // 默认格式存储,通过 tab 和 换行 进行了格式化,方便查看
    3. tb_long_t size = tb_object_writ_to_url(object, "/home/file/json.txt", TB_OBJECT_FORMAT_JSON);
    4.  
    5. // 序列化json object到文件, size 为实际序列化的字节数,如果失败,返回:-1
    6. // 并且压缩存储,去掉冗余的空白字符
    7. tb_long_t size = tb_object_writ_to_url(object, "/home/file/json.txt", TB_OBJECT_FORMAT_JSON | TB_OBJECT_FORMAT_DEFLATE);
    8.  
    9. // 序列化json object到数据buffer,size 为实际序列化的字节数,如果失败,返回:-1
    10. tb_byte_t data[8192] = {0};
    11. tb_long_t size = tb_object_writ_to_data(object, data, 8192, TB_OBJECT_FORMAT_JSON);

    其他格式类似,如下是可以支持的序列化格式:

    • TB_OBJECT_FORMAT_BIN:tbox内部二进制序列化格式,最为节省空间,并且对字符串做了些简单的加密,可以扩展自定义的数据类型
    • TB_OBJECT_FORMAT_BPLIST:apple的二进制plist格式,内部字符串为明文,并且空间利用率不是很高
    • TB_OBJECT_FORMAT_XPLIST:apple的xml文本plist格式
    • TB_OBJECT_FORMAT_XML:tbox内部的xml文本序列化格式,可以扩展自定义的数据类型
    • TB_OBJECT_FORMAT_JSON:json序列化格式

    object对象的字段解析有两种模式,一种是一层层迭代遍历,一种是直接定位到指定字段 迭代遍历,只有array和dictionay需要,他们同样是支持tbox容器库的迭代器模式的,例如:

    1. // 遍历array
    2. tb_for_all (tb_object_ref_t, item, tb_object_array_itor(array))
    3. {
    4. if (item)
    5. {
    6. // ...
    7. }
    8. }
    9.  
    10. // 遍历dictionary
    11. tb_for_all (tb_object_dictionary_item_t*, item, tb_object_dictionary_itor(dictionary))
    12. {
    13. // 获取dictionary的每一个键值对
    14. if (item)
    15. {
    16. // 键名字符串
    17. tb_char_t const* key = item->key;
    18.  
    19. // 值对象, 可以继续迭代下层或直接取值
    20. tb_object_ref_t val = item->val;
    21.  
    22. // ...
    23. }
    24. }

    如果要直接定位某个字段,可以使用tbox的seek模式,支持自定义路径格式:

    1. /* 例如对于这个xml的数据解析
    2.  
    3. <dict>
    4. <key>string</key>
    5. <string>hello wolrd!</string>
    6.  
    7. <key>com.xxx.xxx</key>
    8. <string>hello wolrd!</string>
    9.  
    10. <key>integer</key>
    11. <number>31415926</number>
    12.  
    13. <key>array</key>
    14. <array>
    15. <string>hello wolrd!</string>
    16. <number>31415926</number>
    17. <number>3.1415926</number>
    18. <false/>
    19. <true/>
    20. <dict>
    21. <key>string</key>
    22. <string>hello wolrd!</string>
    23. </dict>
    24. </array>
    25. </dict>
    26.  
    27. * 其对应的字段路径:
    28. * 1. ".string" : hello wolrd!
    29. * 2. ".array[1]" : 31415926
    30. * 3. ".array[5].string" : hello wolrd!
    31. * 4. ".com\\.xxx\\.xxx" : hello wolrd!
    32. */
    33.  
    34. /* seek到指定路径:.array[5].string ,进行解析字段
    35. *
    36. * 这里传TB_OBJECT_TYPE_STRING作为最后一个参数,是为了内部做一次类型检测
    37. * 如果这个字段确实string类型的,才会返回对象,否则返回null,这样上层解析代码
    38. * 看上去更加的简洁,不需要每次解析一个字段,都要外面做一下检测类型
    39. *
    40. * 如果传TB_OBJECT_TYPE_NONE进去,那么不管是不是string对象,都会返回成功
    41. * 这个时候上层如果不做类型检测,只是去字符串,库内部会有断言,但是不影响程序逻辑
    42. * 仅仅是提示下,你现在的处理类型有误。
    43. */
    44. tb_object_ref_t object = tb_object_seek(object, ".array[5].string", TB_OBJECT_TYPE_STRING);
    45. if (object)
    46. {
    47. tb_trace_d("%s", tb_object_string_cstr(object));
    48. }

    其他字段的解析:

    1. /* 解析string类型字段, 取值前,先做类型判断是最安全的方式
    2. * 虽然直接转换也是安全的,类型不对内部直接会返回tb_null
    3. * 但是为了养成良好的编程习惯,在调试模式下,库内部会有检测断言提示类型不匹配
    4. */
    5. if (tb_object_type(object) == TB_OBJECT_TYPE_STRING)
    6. {
    7. tb_char_t const* string = tb_object_string_cstr(object);
    8. }
    9.  
    10. // 解析number类型字段
    11. if (tb_object_type(object) == TB_OBJECT_TYPE_NUMBER)
    12. {
    13. // 获取整型值,如果不是会自动强转,有可能丢失精度
    14. tb_uint32_t value = tb_object_number_uint32(object);
    15.  
    16. // 获取浮点值,如果不是会自动强转
    17. // tb_float_t value = tb_object_number_float(object);
    18.  
    19. // 获取双精度浮点值,如果不是会自动强转
    20. // tb_double_t value = tb_object_number_double(object);
    21. }
    22.  
    23. // 解析boolean类型字段
    24. if (tb_object_type(object) == TB_OBJECT_TYPE_BOOLEAN)
    25. {
    26. // 获取bool值
    27. tb_bool_t value = tb_object_boolean_bool(object);
    28. }
    29.  
    30. // 解析data类型字段
    31. if (tb_object_type(object) == TB_OBJECT_TYPE_DATA)
    32. {
    33. // 获取数据指针
    34. tb_byte_t* data = tb_object_data_getp(object);
    35.  
    36. // 获取数据大小
    37. tb_size_t size = tb_object_data_size(object);
    38. }
    39.  
    40. // 解析date类型字段
    41. if (tb_object_type(object) == TB_OBJECT_TYPE_DATE)
    42. {
    43. // 获取时间戳
    44. tb_time_t time = tb_object_date_time(object);
    45. }
    46.  
    47. // 解析array类型字段
    48. if (tb_object_type(object) == TB_OBJECT_TYPE_ARRAY)
    49. {
    50. // 获取成员数量
    51. tb_size_t count = tb_object_array_size(object);
    52. tb_size_t i = 0;
    53. for (i = 0; i < count; i++)
    54. {
    55. tb_object_ref_t item = tb_object_array_item(object, i);
    56. }
    57. }
    58.  
    59. // 解析dictionary类型字段
    60. if (tb_object_type(object) == TB_OBJECT_TYPE_DICTIONARY)
    61. {
    62. // 获取对象键值
    63. tb_object_ref_t value = tb_object_dictionary_val(object, "key_name");
    64. }