您的位置:首页 > 运维架构

boost.property_tree解析xml的帮助类以及中文解析问题的解决

2015-11-20 11:55 465 查看
boost.property_tree可以用来解析xml和json文件,我主要用它来解析xml文件,它内部封装了号称最快的xml解析器rapid_xml,其解析效率还是很好的。但是在使用过程中却发现各种不好用,归纳一下不好用的地方有这些:
获取不存在的节点时就抛出异常 获取属性值时,要排除属性和注释节点,如果没注意这一点就会抛出异常,让人摸不着头脑。 内存模型有点怪。 默认不支持中文的解析。解析中文会乱码。


ptree获取子节点

  获取子节点接口原型为get_child(node_path),这个node_path从当前路径开始的全路径,父路径和子路径之间通过“.”连接,如“root.sub.child”。需要注意的是get_child获取的是第一个子节点,如果我们要获取子节点列表,则要用路径“root.sub”,这个路径可以获取child的列表。如果获取节点的路径不存在则会抛出异常,这时,如果不希望抛出异常则可以用get_xxx_optional接口,该接口返回一个optional<T>的结果出来,由外面判断是否获取到结果了。

view
sourceprint?

1.
//ptree的optional接口


2.
auto
item = root.get_child_optional(
'Root.Scenes'
);


  该接口返回的是一个optional<ptree>,外面还要判断该节点是否存在,optional对象通过bool操作符来判断该对象是否是无效值,通过指针访问

符'*'来访问该对象的实际内容。建议用optional接口访问xml节点。

view
sourceprint?

1.
//ptree的optional接口


2.
auto
item = root.get_child_optional(
'Root.Scenes'
);


3.
if
(item)


4.
cout<<
'该节点存在'
<<endl;



ptree的内存模型

  ptree维护了一个pair<string, ptree>的子节点列表,first指向的是该节点的TagName,second指向的才是ptree节点,因此在遍历ptree子节点时要注意迭代器的含义。

view
sourceprint?

1.
for
(auto&
data : root)


2.
{


3.
for
(auto&
item : data.second)
//列表元素为pair<string,
ptree>,要用second继续遍历


4.
{


5.
cout<<item.first<<endl;


6.
}


7.
}


  需要注意的是ptree.first可能是属性('<xmlattr>')也可能是注释('<xmlcomment>'),只有非注释类型的节点才能使用获取属性值、子节点等常用接口。


ptree获取属性值

  通过get<T>(attr_name)可以获取属性的值,如果想获取属性的整形值的话,可以用get<int>('Id'),返回一个整数值。有一点要注意如果ptree.first为'<xmlcomment>'时,是没有属性值的,可以通过data()来获取注释内容。如果这个ptree.first不为<xmlattr>时需要在属性名称前面加'<xmlcomment>.',即get<int>('<xmlcomment>.Id')才能正确获取属性值。可以看到获取属性值还是比较繁琐的,在后面要介绍的帮助类中可以简化属性值的获取。如果要获取节点的值则用get_value()接口,该接口用来获取节点的值,如节点:<Field>2</Field>通过get_value()就可以获取值'2'。


解析中文的问题

  ptree只能解析窄字符的xml文件,如果xml文件中含有unicode如中文字符,解析出来就是乱码。解析unicode要用wptree,该类的接口均支持宽字符并且接口和ptree保持一致。要支持中文解析仅仅wptree还不够,还需要一个unicode转换器的帮助,该转换器可以实现宽字符和窄字符的转换,宽窄的互相转换函数有很多实现,不过c++11中有更简单统一的方式实现款窄字符的转换。

c++11中宽窄字符的转换:

view
sourceprint?

1.
std::wstring_convert<std::codecvt<wchar_t,
char
,std::mbstate_t>>
conv


2.


3.
(newstd::codecvt<wchar_t,
char
,std::mbstate_t>(
'CHS'
));


4.
//宽字符转为窄字符


5.
string
str = conv.to_bytes(L
'你好'
);


6.
//窄字符转为宽字符


7.
string
wstr = conv.from_bytes(str);


  boost.property_tree在解析含中文的xml文件时,需要先将该文件转换一下。

  boost解决方法:

view
sourceprint?

01.
#include
'boost/program_options/detail/utf8_codecvt_facet.hpp'


02.
void
ParseChn()


03.
{


04.
std::wifstream
f(fileName);


05.
std::locale
utf8Locale(std::locale(),
new
boost::program_options::detail::utf8_codecvt_facet());


06.
f.imbue(utf8Locale);
//先转换一下


07.


08.
//用wptree去解析


09.
property_tree::wptree
ptree;


10.
property_tree::read_xml(f,
ptree);


11.
}


  这种方法有个缺点就是要引入boost的libboost_program_options库,该库有二十多M,仅仅是为了解决一个中文问题,却要搞得这么麻烦,有点得不偿失。好在c++11提供更简单的方式,用c++11可以这样:

view
sourceprint?

01.
void
Init(
const
wstring&
fileName, wptree& ptree)


02.
{


03.
std::wifstream
f(fileName);


04.
std::locale
utf8Locale(std::locale(),
new
std::codecvt_utf8<wchar_t>);


05.
f.imbue(utf8Locale);
//先转换一下


06.


07.
//用wptree去解析


08.
property_tree::read_xml(f,
ptree);


09.
}


  用c++11就不需要再引入boost的libboost_program_options库了,很简单。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: