object库仅仅提供了对指定对象元素解析模式,使用上较为简单方便,但是有所局限。 如果要支持大数据的xml解析,以及对元素的更灵活控制,可以直接使用tbox底层单独提供的xml模块。

    tbox的xml库提供了两种解析模式:DOM解析和SAX解析。

    DOM方式采用dom对象树,一次性解析到内存,这跟object的类似,但是可以控制所有元素标记。 SAX方式采用外部迭代模式,灵活性和性能更高。并且支持自定路径解析操作,类似xpath,可以选择指定路径,进行解析。

    DOM模式比较简单,只要看下如下例子就能一目了然:

    1. // 初始化流
    2. tb_stream_ref_t istream = tb_stream_init_from_url("http://localhost/file.xml");
    3. if (istream)
    4. {
    5. // 打开流
    6. if (tb_stream_open(istream))
    7. {
    8. // 初始化读取器
    9. tb_xml_reader_ref_t reader = tb_xml_reader_init(istream);
    10. if (reader)
    11. {
    12. // 加载数据, root 为根节点
    13. tb_xml_node_t* root = tb_xml_reader_load(reader);
    14. if (root)
    15. {
    16. // 解析节点操作
    17. // ...
    18. // 释放根节点
    19. tb_xml_node_exit(root);
    20. }
    21. // 释放读取器
    22. tb_xml_reader_exit(reader);
    23. }
    24. }
    25.  
    26. // 释放流
    27. tb_stream_exit(istream);
    28. }

    SAX模式更加的高效、灵活,并且对大数据xml更好的做了支持,因为它是采用迭代器模式, 一边读一边解,只对自己感兴趣的数据进行解析,更加的节省内存,不需要所有都加载到内存中。 因此配合stream,可以实现对网络数据流式解析。

    具体就不多说了,直接上代码吧:

    1. // 初始化流
    2. tb_stream_ref_t istream = tb_stream_init_from_url("http://localhost/file.xml");
    3. if (istream)
    4. {
    5. // 打开流
    6. if (tb_stream_open(istream))
    7. {
    8. // 初始化读取器
    9. tb_xml_reader_ref_t reader = tb_xml_reader_init(istream);
    10. if (reader)
    11. {
    12. // 初始化xml读取器事件
    13. tb_size_t event = TB_XML_READER_EVENT_NONE;
    14. // 遍历所有xml节点元素, 如果返回空事件, 则结束
    15. while ((event = tb_xml_reader_next(reader)))
    16. {
    17. switch (event)
    18. {
    19. // xml文档节点类型事件
    20. case TB_XML_READER_EVENT_DOCUMENT:
    21. {
    22. tb_printf("<?xml version = \"%s\" encoding = \"%s\" ?>\n"
    23. , tb_xml_reader_version(reader), tb_xml_reader_charset(reader));
    24. }
    25. break;
    26. // 文档类型节点类型事件
    27. case TB_XML_READER_EVENT_DOCUMENT_TYPE:
    28. {
    29. tb_printf("<!DOCTYPE>\n");
    30. }
    31. break;
    32. // 空元素节点类型事件,例如: <element/>
    33. case TB_XML_READER_EVENT_ELEMENT_EMPTY:
    34. {
    35. // 节点元素名
    36. tb_char_t const* name = tb_xml_reader_element(reader);
    37.  
    38. // 节点元素属性列表
    39. tb_xml_node_t const* attr = tb_xml_reader_attributes(reader);
    40.  
    41. // xml节点层次,用于显示缩进排版
    42. tb_size_t t = tb_xml_reader_level(reader);
    43. while (t--) tb_printf("\t");
    44.  
    45. // 遍历所有元素属性
    46. if (!attr) tb_printf("<%s/>\n", name);
    47. else
    48. {
    49. tb_printf("<%s", name);
    50. for (; attr; attr = attr->next)
    51. tb_printf(" %s = \"%s\"", tb_pstring_cstr(&attr->name), tb_pstring_cstr(&attr->data));
    52. tb_printf("/>\n");
    53. }
    54. }
    55. break;
    56. // 元素开始节点事件,例如: <element> ...
    57. case TB_XML_READER_EVENT_ELEMENT_BEG:
    58. {
    59. // 节点元素名
    60. tb_char_t const* name = tb_xml_reader_element(reader);
    61.  
    62. // 节点元素属性列表
    63. tb_xml_node_t const* attr = tb_xml_reader_attributes(reader);
    64.  
    65. // xml节点层次,用于显示缩进排版
    66. tb_size_t t = tb_xml_reader_level(reader) - 1;
    67. while (t--) tb_printf("\t");
    68.  
    69. // 遍历所有元素属性
    70. if (!attr) tb_printf("<%s>\n", name);
    71. else
    72. {
    73. tb_printf("<%s", name);
    74. for (; attr; attr = attr->next)
    75. tb_printf(" %s = \"%s\"", tb_pstring_cstr(&attr->name), tb_pstring_cstr(&attr->data));
    76. tb_printf(">\n");
    77. }
    78. }
    79. break;
    80. // 元素结束节点事件,例如:.. </element>
    81. case TB_XML_READER_EVENT_ELEMENT_END:
    82. {
    83. tb_size_t t = tb_xml_reader_level(reader);
    84. while (t--) tb_printf("\t");
    85. tb_printf("</%s>\n", tb_xml_reader_element(reader));
    86. }
    87. break;
    88. // 文本节点事件
    89. case TB_XML_READER_EVENT_TEXT:
    90. {
    91. tb_size_t t = tb_xml_reader_level(reader);
    92. while (t--) tb_printf("\t");
    93. tb_printf("%s", tb_xml_reader_text(reader));
    94. tb_printf("\n");
    95. }
    96. break;
    97. // CDATA节点事件, 例如: <!CDATA[data]>
    98. case TB_XML_READER_EVENT_CDATA:
    99. {
    100. tb_size_t t = tb_xml_reader_level(reader);
    101. while (t--) tb_printf("\t");
    102. tb_printf("<![CDATA[%s]]>", tb_xml_reader_cdata(reader));
    103. tb_printf("\n");
    104. }
    105. break;
    106. // 注释节点事件,例如: <!-- comment -->
    107. case TB_XML_READER_EVENT_COMMENT:
    108. {
    109. tb_size_t t = tb_xml_reader_level(reader);
    110. while (t--) tb_printf("\t");
    111. tb_printf("<!--%s-->", tb_xml_reader_comment(reader));
    112. tb_printf("\n");
    113. }
    114. break;
    115. default:
    116. break;
    117. }
    118. }
    119. // 释放读取器
    120. tb_xml_reader_exit(reader);
    121. }
    122. }
    123.  
    124. // 释放流
    125. tb_stream_exit(istream);
    126. }

    如果想针对性进行解析,可以通过tb_xml_reader_goto定位到指定的path路径开始解析:

    1. // 初始化流
    2. tb_stream_ref_t istream = tb_stream_init_from_url("http://localhost/file.xml");
    3. if (istream)
    4. {
    5. // 打开流
    6. if (tb_stream_open(istream))
    7. {
    8. // 初始化读取器
    9. tb_xml_reader_ref_t reader = tb_xml_reader_init(istream);
    10. if (reader)
    11. {
    12. // 将reader跳转到指定路径
    13. if (tb_xml_reader_goto(reader, "/root/node/data"))
    14. {
    15. // 加载数据, root 为根节点
    16. tb_xml_node_t* root = tb_xml_reader_load(reader);
    17. if (root)
    18. {
    19. // 解析节点操作
    20. // ...
    21. // 释放根节点
    22. tb_xml_node_exit(root);
    23. }
    24. }
    25. // 释放读取器
    26. tb_xml_reader_exit(reader);
    27. }
    28. }
    29. // 释放流
    30. tb_stream_exit(istream);
    31. }

    其中的tb_xml_node_t节点类型,其实就是一个树形链表,如果你一次性加载了整个对象树, 也是可以很方便的对其进行遍历的:

    1. // 节点类型定义描述,其他的所有节点都是继承此节点
    2. typedef struct __tb_xml_node_t
    3. {
    4. /// 节点的类型
    5. tb_size_t type;
    6. /// 节点的名字
    7. tb_pstring_t name;
    8. /// 节点的数据
    9. tb_pstring_t data;
    10. /// 下个节点,单链表
    11. struct __tb_xml_node_t* next;
    12. // 子节点的头部,单链表
    13. struct __tb_xml_node_t* chead;
    14. // 子节点的尾部
    15. struct __tb_xml_node_t* ctail;
    16. // 子节点的数量
    17. tb_size_t csize;
    18. // 属性节点的头部,单链表
    19. struct __tb_xml_node_t* ahead;
    20. // 属性节点的尾部
    21. struct __tb_xml_node_t* atail;
    22. // 属性节点的数量
    23. tb_size_t asize;
    24. /// 父节点
    25. struct __tb_xml_node_t* parent;
    26. }tb_xml_node_t;

    遍历所有子节点:

    1. tb_xml_node_t* head = node->chead;
    2. for (node = head; node; node = node->next)
    3. {
    4. // 这里只处理元素节点:<element>...</element> 或者 <element/>
    5. if (node->type == TB_XML_NODE_TYPE_ELEMENT)
    6. {
    7. // 元素节点的名字大小
    8. tb_size_t m = tb_pstring_size(&node->name);
    9. // 打印元素节点名子
    10. tb_trace_d("%s", tb_pstring_cstr(&node->name));
    11. }
    12. }

    遍历所有属性节点:

    1. tb_xml_node_t* head = node->ahead;
    2. for (node = head; node; node = node->next)
    3. {
    4. // 打印属性节点的名字和数据,例如: attr_name="data"
    5. tb_trace_d("%s=\"%s\"", tb_pstring_cstr(&node->name), tb_pstring_cstr(&node->data));
    6. }