zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    NBUT 1120 Reimu's Teleport (线段树)
    NBUT 1119 Patchouli's Books (STL应用)
    NBUT 1118 Marisa's Affair (排序统计,水)
    NBUT 1117 Kotiya's Incantation(字符输入处理)
    NBUT 1115 Cirno's Trick (水)
    NBUT 1114 Alice's Puppets(排序统计,水)
    188 Best Time to Buy and Sell Stock IV 买卖股票的最佳时机 IV
    187 Repeated DNA Sequences 重复的DNA序列
    179 Largest Number 把数组排成最大的数
    174 Dungeon Game 地下城游戏
  • 原文地址:https://www.cnblogs.com/ye-ming/p/7082607.html
Copyright © 2011-2022 走看看