• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            C++分析研究  
            C++
            日歷
            <2014年1月>
            2930311234
            567891011
            12131415161718
            19202122232425
            2627282930311
            2345678
            統計
            • 隨筆 - 92
            • 文章 - 4
            • 評論 - 4
            • 引用 - 0

            導航

            常用鏈接

            留言簿

            隨筆檔案

            文章檔案

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

             

              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的結果出來,由外面判斷是否獲取到結果托福答案 www.jamo123.com

              //ptree的optional接口

              auto item = root.get_child_optional("Root.Scenes");

              該接口返回的是一個optional,外面還要判斷該節點是否存在,optional對象通過bool操作符來判斷該對象是否是無效值,通過指針訪問

              符"*"來訪問該對象的實際內容。建議用optional接口訪問xml節點。

              //ptree的optional接口

              auto item = root.get_child_optional("Root.Scenes");

              if(item)

              cout<<"該節點存在"<

              ptree的內存模型

              ptree維護了一個pair的子節點列表,first指向的是該節點的TagName,second指向的才是ptree節點,因此在遍歷ptree子節點時要注意迭代器的含義。

              for (auto& data : root)

              {

              for (auto& item : data.second) //列表元素為pair,要用second繼續遍歷

              {

              cout<

              }

              }

              需要注意的是ptree.first可能是屬性("")也可能是注釋(""),只有非注釋類型的節點才能使用獲取屬性值、子節點等常用接口。

              ptree獲取屬性值

              通過get(attr_name)可以獲取屬性的值,如果想獲取屬性的整形值的話,可以用get("Id"),返回一個整數值。有一點要注意如果ptree.first為""時,是沒有屬性值的,可以通過data()來獲取注釋內容。如果這個ptree.first不為時需要在屬性名稱前面加".",即get(".Id")才能正確獲取屬性值。可以看到獲取屬性值還是比較繁瑣的,在后面要介紹的幫助類中可以簡化屬性值的獲取。如果要獲取節點的值則用get_value()接口,該接口用來獲取節點的值,如節點:2通過get_value()就可以獲取值"2"。

              解析中文的問題

              ptree只能解析窄字符的xml文件,如果xml文件中含有unicode如中文字符,解析出來就是亂碼。解析unicode要用wptree,該類的接口均支持寬字符并且接口和ptree保持一致。要支持中文解析僅僅wptree還不夠,還需要一個unicode轉換器的幫助,該轉換器可以實現寬字符和窄字符的轉換,寬窄的互相轉換函數有很多實現,不過c++11中有更簡單統一的方式實現寬窄字符的轉換。

              c++11中寬窄字符的轉換:

              std::wstring_convert> conv

              (newstd::codecvt("CHS"));

              //寬字符轉為窄字符

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

              //窄字符轉為寬字符

              string wstr = conv.from_bytes(str);

              boost.property_tree在解析含中文的xml文件時,需要先將該文件轉換一下。

              boost解決方法:

              #include "boost/program_options/detail/utf8_codecvt_facet.hpp"

              void ParseChn()

              {

              std::wifstream f(fileName);

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

              f.imbue(utf8Locale); //先轉換一下

              //用wptree去解析

              property_tree::wptree ptree;

              property_tree::read_xml(f, ptree);

              }

              這種方法有個缺點就是要引入boost的libboost_program_options庫,該庫有二十多M,僅僅是為了解決一個中文問題,卻要搞得這么麻煩,有點得不償失。好在c++11提供更簡單的方式,用c++11可以這樣:

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

              {

              std::wifstream f(fileName);

              std::locale utf8Locale(std::locale(), new std::codecvt_utf8);

              f.imbue(utf8Locale); //先轉換一下

              //用wptree去解析

              property_tree::read_xml(f, ptree);

              }

              用c++11就不需要再引入boost的libboost_program_options庫了,很簡單。

              property_tree的幫助類

              property_tree的幫助類解決了前面提到的問題:

              用c++11解決中文解析問題

              簡化屬性的獲取

              增加一些操作接口,比如一些查找接口

              避免拋出異常,全部返回optional對象

              隔離了底層繁瑣的操作接口,提供統一、簡潔的高層接口,使用更加方便。

              下面來看看這個幫助類是如何實現的吧:

              #include

              #include

              using namespace boost;

              using namespace boost::property_tree;

              #include

              #include

              #include

              #include

              using namespace std;

              const wstring XMLATTR = L"";

              const wstring XMLCOMMENT = L"";

              const wstring XMLATTR_DOT = L".";

              const wstring XMLCOMMENT_DOT = L".";

              class ConfigParser

              {

              public:

              ConfigParser() : m_conv(new code_type("CHS"))

              {

              }

              ~ConfigParser()

              {

              }

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

              {

              std::wifstream f(fileName);

              std::locale utf8Locale(std::locale(), new std::codecvt_utf8);

              f.imbue(utf8Locale); //先轉換一下

              wcout.imbue(std::locale("chs")); //初始化cout為中文輸出格式

              //用wptree去解析

              property_tree::read_xml(f, ptree);

              }

              // convert UTF-8 string to wstring

              std::wstring to_wstr(const std::string& str)

              {

              return m_conv.from_bytes(str);

              }

              // convert wstring to UTF-8 string

              std::string to_str(const std::wstring& str)

              {

              return m_conv.to_bytes(str);

              }

              //獲取子節點列表

              auto Descendants(const wptree& root, const wstring& key)->decltype(root.get_child_optional(key))

              {

              return root.get_child_optional(key);

              }

              //根據子節點屬性獲取子節點列表

              template

              vector GetChildsByAttr(const wptree& parant, const wstring& tagName, const wstring& attrName, const T& attrVal)

              {

              vector v;

              for (auto& child : parant)

              {

              if (child.first != tagName)

              continue;

              auto attr = Attribute(child, attrName);

              if (attr&&*attr == attrVal)

              v.push_back(child.second);

              }

              return v;

              }

              //獲取節點的某個屬性值

              template

              optional Attribute(const wptree& node, const wstring& attrName)

              {

              return node.get_optional(XMLATTR_DOT + attrName);

              }

              //獲取節點的某個屬性值,默認為string

              optional Attribute(const wptree& node, const wstring& attrName)

              {

              return Attribute(node, attrName);

              }

              //獲取value_type的某個屬性值

              template

              optional Attribute(const wptree::value_type& pair, const wstring& attrName)

              {

              if (pair.first == XMLATTR)

              return pair.second.get_optional(attrName);

              else if (pair.first == XMLCOMMENT)

              return optional();

              else

              return pair.second.get_optional(XMLATTR_DOT + attrName);

              }

              //獲取value_type的某個屬性值,默認為string

              optional Attribute(const wptree::value_type& pair, const wstring& attrName)

              {

              return Attribute(pair, attrName);

              }

              //根據某個屬性生成一個的multimap

              template>

              multimap MakeMapByAttr(const wptree& root, const wstring& key, const wstring& attrName, F predict = [](wstring& str){return true; })

              {

              multimap resultMap;

              auto list = Descendants(root, key);

              if (!list)

              return resultMap;

              for (auto& item : *list)

              {

              auto attr = Attribute(item, attrName);

              if (attr&&predict(*attr))

              resultMap.insert(std::make_pair(*attr, item.second));

              }

              return resultMap;

              }

              private:

              using code_type = std::codecvt;

              std::wstring_convert m_conv;

              };

              View Code

              測試文件test.xml和測試代碼:

              void Test()

              {

              wptree pt; pt.get_value()

              ConfigParser parser;

              parser.Init(L"test1.xml", pt); //解決中文問題,要轉換為unicode解析

              auto scenes = parser.Descendants(pt, L"Root.Scenes"); //返回的是optional

              if (!scenes)

              return;

              for (auto& scene : *scenes)

              {

              auto s = parser.Attribute(scene, L"Name"); //獲取Name屬性,返回的是optional

              if (s)

              {

              wcout << *s << endl;

              }

              auto dataList = parser.Descendants(scene.second, L"DataSource"); //獲取第一個子節點

              if (!dataList)

              continue;

              for (auto& data : *dataList)

              {

              for (auto& item : data.second)

              {

              auto id = parser.Attribute(item, L"Id");

              auto fileName = parser.Attribute(item, L"FileName");

              if (id)

              {

              wcout << *id << L" " << *fileName << endl; //打印id和filename

              }

              }

              }

              }

              }

              測試結果:


              可以看到通過幫助類,無需使用原生接口就可以很方便的實現節點的訪問與操作。使用者不必關注內部細節,根據統一而簡潔的接口就可以操作xml文件了。

              一點題外話,基于這個幫助類再結合linq to object可以輕松的實現linq to xml:

              //獲取子節點SubNode的屬性ID的值為0x10000D的項并打印出該項的Type屬性

              from(node.Descendants("Root.SubNode")).where([](XNode& node)

              {

              auto s = node.Attribute("ID");

              return s&&*s == "0x10000D";

              }).for_each([](XNode& node)

              {

              auto s = node.Attribute("Type");

              if (s)

              cout << *s << endl;

              });

            posted on 2014-03-11 16:27 HAOSOLA 閱讀(5135) 評論(0)  編輯 收藏 引用
             
            Copyright © HAOSOLA Powered by: 博客園 模板提供:滬江博客
            PK10開獎 PK10開獎
            国产精品一区二区久久精品无码| 成人午夜精品无码区久久 | 成人国内精品久久久久影院| 久久久久久国产a免费观看黄色大片 | 精品久久久久久亚洲精品 | 一97日本道伊人久久综合影院| 综合久久精品色| 97久久天天综合色天天综合色hd| 国产L精品国产亚洲区久久| 最新久久免费视频| 久久久九九有精品国产| 婷婷国产天堂久久综合五月| 99久久国产综合精品麻豆| 中文国产成人精品久久亚洲精品AⅤ无码精品 | 无码人妻少妇久久中文字幕蜜桃| 91久久精品电影| 少妇人妻88久久中文字幕| 欧美久久久久久午夜精品| 久久99精品久久久久久hb无码| 久久狠狠一本精品综合网| 国产精品视频久久久| 久久这里都是精品| 久久综合伊人77777麻豆| 亚洲国产精品久久久久久| 中文字幕日本人妻久久久免费 | 久久中文骚妇内射| 亚洲精品久久久www| 久久99精品国产麻豆不卡| 77777亚洲午夜久久多喷| 久久久久99精品成人片| 久久99国产精品一区二区| 午夜精品久久久久久中宇| 久久精品免费一区二区| 亚洲精品午夜国产va久久| 久久影院午夜理论片无码| 久久精品亚洲福利| 久久久久国产一区二区三区| 久久国产乱子伦精品免费午夜| 国产亚洲精午夜久久久久久| 久久精品国产只有精品66| 久久精品国产亚洲一区二区三区|