自己写的简单xml解析器

已经自我放逐好几年了.打算去上班得了.在最后的自由日子里,做点有意义的事吧...



先来下载地址

http://www.kuaipan.cn/file/id_12470514853353274.htm



已经在很多正式,非正式的场合用过了.干脆开源得了.BSD授权.

代码比较久远,最后一次修改也在4~5年前了.写的比较BT,只有gcc/vc/icl能编译...

不过性能和易用性还是不错的.之前我测试过的,只有几个in place的xml解析器稍微比我的快一点点.

下面是示例代码:
C/C++ code?

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 // xml-test.cpp``#include <stdio.h>``#include "xml.h"``// 自定义FILE*输出策略``class cfile_writer {``FILE *_fp;``cfile_writer &operator = (``const cfile_writer& );``cfile_writer(``const cfile_writer& );``public``:``cfile_writer(``FILE *fp ) : _fp(fp) {``fputs``(``"-----------------\n"``, _fp );``}``~cfile_writer() {``fputs``(``"\n"``, _fp );``}``// 策略不用预分配空间``// 如果为1, 在输出前会计算要占空间大小, 并调用resize接口进行预分配.``static const int need_pre_allocate = 0;``// 预分配接口``bool resize(``size_t size )``const {``return true``; }``// 输出一个字符``void write(``char value )``const {``fputc``( value, _fp );``}``// 输出一个字符串, 长度由size指定``void write(``const char *value,``size_t size )``const {``fwrite``( value, 1, size, _fp );``}``};``int main() {``using namespace cpp::utils;``const char xml_string[] =``"<root attr=\"root attr\"><node prop=\"234\"/>text content<!-- comment --></root>"``;``xml x;``// 解析xml_string, 用不同的reader策略可以从不同的源中读数据``// 也可以自定义读策略, 以适应不同的需求``// 解析成功返回true.如果只有部分解析成功时虽然返回false,但已经解析成功的内容仍然可用``// 如果宏XML_WITH_PARSE_STATUS设置为1(默认为0).可以从x.info()中得到解析器停止的位置,方便调试.但会降低解析器性能.``x.parse( xml_reader( xml_string ) );``xml x2;``x2.push_back( xml::tag(``"root-x2"``) );``// 直接向空xml对象中添加标签``x2(``"root-x2"``).push_back( xml::text(``"text value"``) );``x2.write( cfile_writer( stderr ) );``// 输出/root/node[prop]的值``// ()运算符为标签查找,返回指定名称的第一个标签.[]运算符为属性查找,返回指定名称的属性.``printf``(``"/root/node[prop] = [%s]\n"``, x(``"root"``)(``"node"``)[``"prop"``].value().c_str() );``// 这里使用了null object模式,所以无需检查每一步的返回结果,不会因为访问非法节点而产生异常.简化使用``printf``(``"null object test:[%s]\n"``, x(``"roxxot"``)(``"noeede"``)[``"prop"``].value().c_str() );``// 把root标签转成其迭代器(&运算符)``xml::tag_iterator root_tag = &x(``"root"``);``// 迭代所有子节点``for``( xml::node_iterator node = x.root()->begin(); node != x.root()->end(); ++node ) {``// xml::node_iterator为通用节点迭代器, 可以指向任何类型的节点.``// 并可以转型成任意的其它迭代器. 但如果指向的节点类型和目标迭代器类型不符, 则会自动指向下一个合法的节点``// 比如: <abc/><!--comment-->``// 这里有两个节点,一个abc标签,一个注释.``// 如果有当前node迭代器指向abc标签.``// 把node转成xml::tag_iterator类型时,则指向的节点不变.``// 如果转成xml::comment_iterator时则会指向后面的注释.``// 如果转成其它不存在类型的节点,则会指向容器的末尾.``printf``(``"node type: %d\t"``, node->type );``switch``( node->type ) {``case xml::_TYPE_TAG:``printf``(``"tag name:%s\n"``, xml::tag_iterator(node)->name().c_str() );``break``;``case xml::_TYPE_COMMENT:``printf``(``"comment:%s\n"``, xml::comment_iterator(node)->text().c_str() );``break``;``case xml::_TYPE_TEXT:``printf``(``"text:%s\n"``, xml::text_iterator(node)->text().c_str() );``break``;``case xml::_TYPE_ATTRIBUTE:``printf``(``"attribute:%s=%s\n"``, xml::attribute_iterator(node)->name().c_str(), xml::attribute_iterator(node)->value().c_str() );``break``;``default``:``printf``(``"unknown type\n" );``break``;``}``};``// 迭代所有子标签``for``( xml::tag_iterator tag = x.root()->begin(); tag != x.root()->end(); ++tag ) {``// 专用类型的迭代器只能遍历此类型的节点``printf``(``"tag:%s\n"``, tag->name().c_str() );``}``// 在/root/node下添加abc标签, 并保存指向标签的迭代器``xml::tag_iterator abc_tag = x(``"root"``)(``"node"``).push_back( xml::tag(``"abc" ) );``// 用abc_tag迭代器向abc标签添加属性``abc_tag->push_back( xml::attribute(``"tag-prop"``,``"value abcdefg" ) );``// 在abc标签前插入注释``abc_tag->parent().insert( abc_tag, xml::comment(``"tag-prop comment" ) );``// 把xml_string解析出来,并将结果放到abc_tag所指向的标签里``abc_tag->parse( xml_reader( xml_string ) );``// 深拷贝x2对象中的根节点到abc标签中,实现跨xml对象进行节点复制``abc_tag->push_front_copy( x2.root() );``// 输出abc_tag指向的标签, 第二个参数true表示只输出内容标签的内容,不包含标签本身及属性``abc_tag->write( cfile_writer( stdout ),``true );``// 删除第一个子节点``abc_tag->erase( abc_tag->begin() );``abc_tag->write( cfile_writer( stdout ),``true );``// 不能直接删除孙节点``x.erase( xml::tag_iterator(abc_tag->begin()) );``// 转型成xml::tag_iterator是因为abc的第一个节点是属性.删除不直观.用标记会明显点``abc_tag->write( cfile_writer( stdout ) );``// 没有删掉``// 递归删除可以成功``x.recursion_erase( xml::tag_iterator(abc_tag->begin()) );``abc_tag->write( cfile_writer( stdout ) );``// 已经删除成功``return 0;``}

只支持基本语法,很多东西不支持.比如:CDATA不支持,自定义转意也不支持...

用来做配置文件还是不错.

原文地址
原文链接: https://www.cnblogs.com/linlf03/archive/2013/01/03/2843273.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/74406

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 下午4:23
下一篇 2023年2月9日 下午4:23

相关推荐