json、xml、plist的解析和生成

object庫,提供運行時對象支持,經過引用計數維護全部對象。只要是繼承自tb_object_t的對象類型都是能夠通過擴展實現序列化和反序列化。git

庫內部也已經提供了經常使用的對象類型:github

  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文件到內存:json

// 從文件讀取json數據到內存,json_root爲整個根對象
tb_object_ref_t json_root = tb_object_read_from_url("/home/file/json.txt");

// 從http讀取json數據到內存,json_root爲整個根對象
// tb_object_ref_t json_root = tb_object_read_from_url("http://localhost/file/json.txt");

// 從數據讀取json數據到內存,json_root爲整個根對象
// tb_object_ref_t json_root = tb_object_read_from_data(data, size);

// 從stream讀取json數據到內存,json_root爲整個根對象
// tb_object_ref_t json_root = tb_object_read(stream);

if (json_root)
{
    // 將json_root的全部數據格式打印到終端,通常調試使用
    tb_object_dump(json_root);

    // 釋放json_root對象,object跟CoreFoundation同樣是有引用計數的
    // 這裏json_root沒有被其餘引用,因此會被立馬釋放掉
    tb_object_exit(json_root);
}

怎麼樣簡單吧,若是要解析plist文件, 也是相似,只需換成plist 文件的url就好了 庫內部回去自動檢測文件格式,進行相應地解析工做,上層都是通用的object對象樹 而且能夠支持xplist(xml格式)、bplist(二進制格式)兩種格式。數組

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

對於序列化到文件,也很簡單:安全

// 序列化json object到文件, size 爲實際序列化的字節數,若是失敗,返回:-1
// 默認格式存儲,經過 tab 和 換行 進行了格式化,方便查看
tb_long_t size = tb_object_writ_to_url(object, "/home/file/json.txt", TB_OBJECT_FORMAT_JSON);

// 序列化json object到文件, size 爲實際序列化的字節數,若是失敗,返回:-1
// 而且壓縮存儲,去掉冗餘的空白字符
tb_long_t size = tb_object_writ_to_url(object, "/home/file/json.txt", TB_OBJECT_FORMAT_JSON | TB_OBJECT_FORMAT_DEFLATE);

// 序列化json object到數據buffer,size 爲實際序列化的字節數,若是失敗,返回:-1
tb_byte_t data[8192] = {0};
tb_long_t size = tb_object_writ_to_data(object, data, 8192, TB_OBJECT_FORMAT_JSON);

其餘格式相似,以下是能夠支持的序列化格式:app

  • 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容器庫的迭代器模式的,例如:ui

// 遍歷array
tb_for_all (tb_object_ref_t, item, tb_object_array_itor(array))
{
    if (item)
    {
        // ...
    }
}

// 遍歷dictionary
tb_for_all (tb_object_dictionary_item_t*, item, tb_object_dictionary_itor(dictionary))
{
    // 獲取dictionary的每個鍵值對
    if (item)
    {
        // 鍵名字符串
        tb_char_t const*    key = item->key;

        // 值對象, 能夠繼續迭代下層或直接取值
        tb_object_ref_t     val = item->val;

        // ...
    }
}

若是要直接定位某個字段,可使用tbox的seek模式,支持自定義路徑格式:加密

/* 例如對於這個xml的數據解析

    <dict>
        <key>string</key>
        <string>hello wolrd!</string>

        <key>com.xxx.xxx</key>
        <string>hello wolrd!</string>

        <key>integer</key>
        <number>31415926</number>

        <key>array</key>
        <array>
            <string>hello wolrd!</string>
            <number>31415926</number>
            <number>3.1415926</number>
            <false/>
            <true/>
            <dict>
                <key>string</key>
                <string>hello wolrd!</string>
            </dict>
        </array>
    </dict>

 * 其對應的字段路徑:
 * 1. ".string"             : hello wolrd!
 * 2. ".array[1]"           : 31415926
 * 3. ".array[5].string"    : hello wolrd!
 * 4. ".com\\.xxx\\.xxx"    : hello wolrd!
 */

/* seek到指定路徑:.array[5].string ,進行解析字段
 *
 * 這裏傳TB_OBJECT_TYPE_STRING做爲最後一個參數,是爲了內部作一次類型檢測
 * 若是這個字段確實string類型的,纔會返回對象,不然返回null,這樣上層解析代碼
 * 看上去更加的簡潔,不須要每次解析一個字段,都要外面作一下檢測類型
 * 
 * 若是傳TB_OBJECT_TYPE_NONE進去,那麼無論是否是string對象,都會返回成功
 * 這個時候上層若是不作類型檢測,只是去字符串,庫內部會有斷言,可是不影響程序邏輯
 * 僅僅是提示下,你如今的處理類型有誤。
 */
tb_object_ref_t object = tb_object_seek(object, ".array[5].string", TB_OBJECT_TYPE_STRING);
if (object)
{
    tb_trace_d("%s", tb_object_string_cstr(object));
}

其餘字段的解析:url

/* 解析string類型字段, 取值前,先作類型判斷是最安全的方式
 * 雖然直接轉換也是安全的,類型不對內部直接會返回tb_null
 * 可是爲了養成良好的編程習慣,在調試模式下,庫內部會有檢測斷言提示類型不匹配
 */
if (tb_object_type(object) == TB_OBJECT_TYPE_STRING)
{
    tb_char_t const* string = tb_object_string_cstr(object);
}

// 解析number類型字段
if (tb_object_type(object) == TB_OBJECT_TYPE_NUMBER)
{
    // 獲取整型值,若是不是會自動強轉,有可能丟失精度
    tb_uint32_t value = tb_object_number_uint32(object);

    // 獲取浮點值,若是不是會自動強轉
//    tb_float_t value = tb_object_number_float(object);

    // 獲取雙精度浮點值,若是不是會自動強轉
//    tb_double_t value = tb_object_number_double(object);
}

// 解析boolean類型字段
if (tb_object_type(object) == TB_OBJECT_TYPE_BOOLEAN)
{
    // 獲取bool值
    tb_bool_t value = tb_object_boolean_bool(object);
}

// 解析data類型字段
if (tb_object_type(object) == TB_OBJECT_TYPE_DATA)
{
    // 獲取數據指針
    tb_byte_t* data = tb_object_data_getp(object);

    // 獲取數據大小
    tb_size_t size = tb_object_data_size(object);
}

// 解析date類型字段
if (tb_object_type(object) == TB_OBJECT_TYPE_DATE)
{
    // 獲取時間戳
    tb_time_t time = tb_object_date_time(object);
}

// 解析array類型字段
if (tb_object_type(object) == TB_OBJECT_TYPE_ARRAY)
{
    // 獲取成員數量
    tb_size_t count = tb_object_array_size(object);
    tb_size_t i = 0;
    for (i = 0; i < count; i++)
    {
        tb_object_ref_t item = tb_object_array_item(object, i);
    }
}

// 解析dictionary類型字段
if (tb_object_type(object) == TB_OBJECT_TYPE_DICTIONARY)
{
    // 獲取對象鍵值
    tb_object_ref_t value = tb_object_dictionary_val(object, "key_name");
}

相關文章
相關標籤/搜索