// xml-test.cpp
#include
#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[] = "text content" ;
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标签,一个注释.
// 如果有当前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;
}
|