• boost.property_tree的高级用法(你们没见过的操作)


    版权声明:本文为博主原创文章,未经博主允许不得转载。

    前一阵写项目,终于将这个boost下的xml读取类完成了,由于网上对property_trees的讲解很少,最多也就到get_child这个层面,所以我写起来很困难,前前后后用了两个星期左右吧,后来发现property_trees要是用好了操作特别骚,而且思路还挺简单的。

    目前网上基本上都是在教你读这样的xml

    <root>  
     <delfile>  
      <filenum> 35 </filenum>  
      <paths>  
       <path>   
        <pathname>/tmp/tmp0/</pathname>  
        <before_hours> 0 </before_hours>  
       </path>     
     </delfile>  
     <backup>  
      <backuptime> 23:59 </backuptime>  
     </backup>  
    </root>  

    这样的xml很low,没有任何的信息。一般的xml都是这样的

    <?xml version="1.0" encoding="utf-8"?>
    <root>
        <Item name="project" desc="">
            <ChildItem name="project1" desc="file size" datatype="int">600</ChildItem>
            <ChildItem name="project2" desc="file size" datatype="int">353</ChildItem>
            <ChildItem name="project3" desc="file size" datatype="int">756</ChildItem>
            <ChildItem name="project4" desc="file size" datatype="int">888</ChildItem>
        </Item>
    </Config>

    像这样的xml才有价值,但是这里所有的child都一样,并且包含很多的属性,我们怎么去读取value呢?

    0X01 遍历方法一

    通过遍历读取到map里,再从map中赛选数据

    ptree m_pt;
    string strAttrName
    BOOST_FOREACH(ptree::value_type
    &v1, m_pt.get_child(L"root")) { if (v1.first == L"Item") { strAttrName=v1.second.get<string>(L"<xmlattr>.name"); }
    }

    这样我们就通过FOREACH遍历出来第一层xml的属性的值“project”,属性是('<xmlattr>')注释是('<xmlcomment>')
    那么想在遍历出第二层的属性同样在里面再来一层FOREACH,但是这一层FOREACH要继承上面第一层的value_type的值

    BOOST_FOREACH(wptree::value_type &v2, v1.second)
                {
                    if (v2.first == L"ChildItem")
                    {
                         string strChildAttrName = v2.second.get<wstring>(L"<xmlattr>.name");
                  //取属性
    } }

    取值直接用date()就行,value_type有两个方法,第一个方法是first()取得是节点名例如Item ”,而第二个方法date()取的是节点的属性或者是value。

    string value = v2.second.data();

    最后将两个循环出来的值分别插入两个map里

    ptree m_pt;
    string strAttrName;
    BOOST_FOREACH(ptree::value_type &v1, m_pt.get_child(L"root"))
    {
        if (v1.first == L"Item")
        {
              strAttrName=v1.second.get<string>(L"<xmlattr>.name");
        }
           BOOST_FOREACH(wptree::value_type &v2, v1.second)
                {
                    if (v2.first == L"ChildItem")
                    {
                         string strChildAttrName = v2.second.get<wstring>(L"<xmlattr>.name");//取属性
                         string value = v2.second.data();
                        map1.insert(pair<string, string>(strChildAttrName, value )
                    }
                }
                        m_map2.insert(pair < string, map<string, string>>(strAttrName, map1));
    }                                             

    最后map2就是你得到的xml树,当然你也可以多获得一些属性放进去,并做一些处理。

    0X02 遍历方法二

    如果嫌FOREACH效率太低,你也可以用for循环来遍历xml树

    首先我们要是用到for循环的话,必须用到ptree中的find()方法,但是find()方法没法深入查找,什么叫无法深入查找?就是说你套了两层xml(就像我的例子一样)他就无法查找了,所以我们必须先将最外一层节点去掉

    ptree pt;
    pt = pt.get_child(L"root");

    将节点指向自己,这样就可以去掉最外一层节点。以后需要遍历查找

    for (wptree::assoc_iterator iter = pt.find(L"Item"); iter != pt.not_found() && !bfind; ++iter)
    {
              auto strAttrName = iter->second.get<wstring>(L"<xmlattr>.name");
    }    

    这样可以遍历出在外层的节点的属性

    第二层节点通过第一层节点的迭代器来来迭代

    for (wptree::assoc_iterator iter2 = iter->second.find(L"ChildItem"); iter2 != iter->second.not_found(); ++iter2)
    { auto strChildAttrName
    = iter2->second.get<wstring>(L"<xmlattr>.name");
    }

     具体实现

    for (wptree::assoc_iterator iter = pt.find(L"Item"); iter != pt.not_found() && !bfind; ++iter)
    {
           auto strAttrName = iter->second.get<string>(L"<xmlattr>.name");
        for (wptree::assoc_iterator iter2 = iter->second.find(L"ChildItem"); iter2 != iter->second.not_found(); ++iter2)
           {
              auto strChildAttrName = iter2->second.get<string>(L"<xmlattr>.name");          
        } }

    之后分别输出、修改值、或者存入xml中都可以,但是因为最外层的节点已经删除了,所以我们还得吧最外层的节点找回来

    ptree pt1;
    pt = pt.get_child(L"Config");
    ........
    .......
    pt1.add_child(L"Config", pt);
    m_pt.clear();
    m_pt = pt1;

    必须再建一个ptree,这样加节点的时候才不会乱。

    0X03 增加节点

    增加就特别好说了

    vector<string> vect_str;  
        vector<string>::iterator it;  
      
        vect_str.push_back("111111");  
        vect_str.push_back("222222");  
        vect_str.push_back("333333");  
        vect_str.push_back("444444");  
    
     for (it = vect_str.begin(); it != vect_str.end(); it++) { //迭代vector  
            data.put("<xmlattr>.key",it->data());  
            info.add_child("data",data);  
            data.clear() ;  
        }  
        pt.add_child("root.output.info",info)

    放入map或者vactor里都行,之后遍历增加

    0X04 删除节点

    删除也一样,遍历之后删除节点。

    ptree& persons = pt.get_child("root.persons");
    for(auto it = persons.begin(); it != persons.end();) 
    {
    if(it->second.get<string>("name") == "dad") it = persons.erase(it); else ++it; }

    0X05 修改值

    改也很简单,遍历出所要改的值在节点,直接赋值然后再写回去就行了。

    iter2->second.put_value(value);

    0X06 抛出异常

    增删改查都说完了,再说说异常吧,property_tree的异常分两种,一种是路径错误,一种是值错误很好判断,异常直接告诉你哪个属性等有问题

    try
        {    
            .......
        }
        catch (boost::property_tree::ptree_bad_path& e)
        {
            m_error = e.what();
            return false;
        }
        catch (boost::property_tree::ptree_bad_data& e)
        {
            m_error =e.what();
            return false;
        }

     研究了一个月,我敢说property_tree这个类库我用的国内最熟233333

  • 相关阅读:
    Asp.Net细节性问题技巧精萃
    存储过程(Stored Procedure)及应用
    合并datagrid中内容相同的单元格
    .net 2.0 下发送邮件的方式
    ADO.NET2.0的十大新特性
    sql server 中各个系统表的作用
    DataGrid一些文章的索引,方便查找
    ASP.NET中 WebControls 命名规则
    SQL Server应用程序中的高级SQL注入[转]
    数据操作例子
  • 原文地址:https://www.cnblogs.com/ye-ming/p/7082607.html
Copyright © 2020-2023  润新知