首页 > 代码库 > xml解析
xml解析
object库仅仅提供了对指定对象元素解析模式,使用上较为简单方便,但是有所局限。
如果要支持大数据的xml解析,以及对元素的更灵活控制,可以直接使用tbox底层单独提供的xml模块。
tbox的xml库提供了两种解析模式:DOM解析和SAX解析。
DOM方式采用dom对象树,一次性解析到内存,这跟object的类似,但是可以控制所有元素标记。
SAX方式采用外部迭代模式,灵活性和性能更高。并且支持自定路径解析操作,类似xpath,可以选择指定路径,进行解析。
DOM模式比较简单,只要看下如下例子就能一目了然:
// 初始化流 tb_stream_ref_t istream = tb_stream_init_from_url("http://localhost/file.xml"); if (istream) { // 打开流 if (tb_stream_open(istream)) { // 初始化读取器 tb_xml_reader_ref_t reader = tb_xml_reader_init(istream); if (reader) { // 加载数据, root 为根节点 tb_xml_node_t* root = tb_xml_reader_load(reader); if (root) { // 解析节点操作 // ... // 释放根节点 tb_xml_node_exit(root); } // 释放读取器 tb_xml_reader_exit(reader); } } // 释放流 tb_stream_exit(istream); }
SAX模式更加的高效、灵活,并且对大数据xml更好的做了支持,因为它是采用迭代器模式,
一边读一边解,只对自己感兴趣的数据进行解析,更加的节省内存,不需要所有都加载到内存中。
因此配合stream,可以实现对网络数据流式解析。
具体就不多说了,直接上代码吧:
// 初始化流 tb_stream_ref_t istream = tb_stream_init_from_url("http://localhost/file.xml"); if (istream) { // 打开流 if (tb_stream_open(istream)) { // 初始化读取器 tb_xml_reader_ref_t reader = tb_xml_reader_init(istream); if (reader) { // 初始化xml读取器事件 tb_size_t event = TB_XML_READER_EVENT_NONE; // 遍历所有xml节点元素, 如果返回空事件, 则结束 while ((event = tb_xml_reader_next(reader))) { switch (event) { // xml文档节点类型事件 case TB_XML_READER_EVENT_DOCUMENT: { tb_printf("<?xml version = \"%s\" encoding = \"%s\" ?>\n" , tb_xml_reader_version(reader), tb_xml_reader_charset(reader)); } break; // 文档类型节点类型事件 case TB_XML_READER_EVENT_DOCUMENT_TYPE: { tb_printf("<!DOCTYPE>\n"); } break; // 空元素节点类型事件,例如: <element/> case TB_XML_READER_EVENT_ELEMENT_EMPTY: { // 节点元素名 tb_char_t const* name = tb_xml_reader_element(reader); // 节点元素属性列表 tb_xml_node_t const* attr = tb_xml_reader_attributes(reader); // xml节点层次,用于显示缩进排版 tb_size_t t = tb_xml_reader_level(reader); while (t--) tb_printf("\t"); // 遍历所有元素属性 if (!attr) tb_printf("<%s/>\n", name); else { tb_printf("<%s", name); for (; attr; attr = attr->next) tb_printf(" %s = \"%s\"", tb_pstring_cstr(&attr->name), tb_pstring_cstr(&attr->data)); tb_printf("/>\n"); } } break; // 元素开始节点事件,例如: <element> ... case TB_XML_READER_EVENT_ELEMENT_BEG: { // 节点元素名 tb_char_t const* name = tb_xml_reader_element(reader); // 节点元素属性列表 tb_xml_node_t const* attr = tb_xml_reader_attributes(reader); // xml节点层次,用于显示缩进排版 tb_size_t t = tb_xml_reader_level(reader) - 1; while (t--) tb_printf("\t"); // 遍历所有元素属性 if (!attr) tb_printf("<%s>\n", name); else { tb_printf("<%s", name); for (; attr; attr = attr->next) tb_printf(" %s = \"%s\"", tb_pstring_cstr(&attr->name), tb_pstring_cstr(&attr->data)); tb_printf(">\n"); } } break; // 元素结束节点事件,例如:.. </element> case TB_XML_READER_EVENT_ELEMENT_END: { tb_size_t t = tb_xml_reader_level(reader); while (t--) tb_printf("\t"); tb_printf("</%s>\n", tb_xml_reader_element(reader)); } break; // 文本节点事件 case TB_XML_READER_EVENT_TEXT: { tb_size_t t = tb_xml_reader_level(reader); while (t--) tb_printf("\t"); tb_printf("%s", tb_xml_reader_text(reader)); tb_printf("\n"); } break; // CDATA节点事件, 例如: <!CDATA[data]> case TB_XML_READER_EVENT_CDATA: { tb_size_t t = tb_xml_reader_level(reader); while (t--) tb_printf("\t"); tb_printf("<![CDATA[%s]]>", tb_xml_reader_cdata(reader)); tb_printf("\n"); } break; // 注释节点事件,例如: <!-- comment --> case TB_XML_READER_EVENT_COMMENT: { tb_size_t t = tb_xml_reader_level(reader); while (t--) tb_printf("\t"); tb_printf("<!--%s-->", tb_xml_reader_comment(reader)); tb_printf("\n"); } break; default: break; } } // 释放读取器 tb_xml_reader_exit(reader); } } // 释放流 tb_stream_exit(istream); }
如果想针对性进行解析,可以通过tb_xml_reader_goto定位到指定的path路径开始解析:
// 初始化流 tb_stream_ref_t istream = tb_stream_init_from_url("http://localhost/file.xml"); if (istream) { // 打开流 if (tb_stream_open(istream)) { // 初始化读取器 tb_xml_reader_ref_t reader = tb_xml_reader_init(istream); if (reader) { // 将reader跳转到指定路径 if (tb_xml_reader_goto(reader, "/root/node/data")) { // 加载数据, root 为根节点 tb_xml_node_t* root = tb_xml_reader_load(reader); if (root) { // 解析节点操作 // ... // 释放根节点 tb_xml_node_exit(root); } } // 释放读取器 tb_xml_reader_exit(reader); } } // 释放流 tb_stream_exit(istream); }
其中的tb_xml_node_t节点类型,其实就是一个树形链表,如果你一次性加载了整个对象树,
也是可以很方便的对其进行遍历的:
// 节点类型定义描述,其他的所有节点都是继承此节点 typedef struct __tb_xml_node_t { /// 节点的类型 tb_size_t type; /// 节点的名字 tb_pstring_t name; /// 节点的数据 tb_pstring_t data; /// 下个节点,单链表 struct __tb_xml_node_t* next; // 子节点的头部,单链表 struct __tb_xml_node_t* chead; // 子节点的尾部 struct __tb_xml_node_t* ctail; // 子节点的数量 tb_size_t csize; // 属性节点的头部,单链表 struct __tb_xml_node_t* ahead; // 属性节点的尾部 struct __tb_xml_node_t* atail; // 属性节点的数量 tb_size_t asize; /// 父节点 struct __tb_xml_node_t* parent; }tb_xml_node_t;
遍历所有子节点:
tb_xml_node_t* head = node->chead; for (node = head; node; node = node->next) { // 这里只处理元素节点:<element>...</element> 或者 <element/> if (node->type == TB_XML_NODE_TYPE_ELEMENT) { // 元素节点的名字大小 tb_size_t m = tb_pstring_size(&node->name); // 打印元素节点名子 tb_trace_d("%s", tb_pstring_cstr(&node->name)); }
}
遍历所有属性节点:
tb_xml_node_t* head = node->ahead; for (node = head; node; node = node->next) { // 打印属性节点的名字和数据,例如: attr_name="data" tb_trace_d("%s=\"%s\"", tb_pstring_cstr(&node->name), tb_pstring_cstr(&node->data)); }
xml解析
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。