




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第C++實(shí)現(xiàn)xml解析器示例詳解目錄xml格式簡(jiǎn)單介紹xml格式解析過(guò)程淺析代碼實(shí)現(xiàn)實(shí)現(xiàn)存儲(chǔ)解析數(shù)據(jù)的類Element關(guān)鍵代碼1實(shí)現(xiàn)整體的解析關(guān)鍵代碼2解析所有元素開(kāi)發(fā)技巧有關(guān)C++的優(yōu)化額外注意
xml格式簡(jiǎn)單介紹
xmlversion="1.0"
!--這是注釋--
workflow
workname="1"switch="on"
pluginname="echoplugin.so"switch="on"/
/work
/workflow
我們來(lái)簡(jiǎn)單觀察下上面的xml文件,xml格式和html格式十分類似,一般用于存儲(chǔ)需要屬性的配置或者需要多個(gè)嵌套關(guān)系的配置。
xml一般使用于項(xiàng)目的配置文件,相比于其他的ini格式或者yaml格式,它的優(yōu)勢(shì)在于可以將一個(gè)標(biāo)簽擁有多個(gè)屬性,比如上述xml文件格式是用于配置工作流的,其中有name屬性和switch屬性,且再work標(biāo)簽中又嵌套了plugin標(biāo)簽,相比較其他配置文件格式是要靈活很多的。
具體的應(yīng)用場(chǎng)景有很多,比如使用過(guò)Java中Mybatis的同學(xué)應(yīng)該清楚,Mybatis的配置文件就是xml格式,而且也可以通過(guò)xml格式進(jìn)行sql語(yǔ)句的編寫(xiě),同樣Java的maven項(xiàng)目的配置文件也是采用的xml文件進(jìn)行配置。
而我為什么要寫(xiě)一個(gè)xml解析器呢?很明顯,我今后要寫(xiě)的C++項(xiàng)目需要用到。
xml格式解析過(guò)程淺析
同樣回到之前的那段代碼,實(shí)際上已經(jīng)把xml文件格式的不同情況都列出來(lái)了。
從整體上看,所有的xml標(biāo)簽分為:
xml聲明(包含版本、編碼等信息)注釋xml元素:1.單標(biāo)簽元素。2.成對(duì)標(biāo)簽元素。
其中xml聲明和注釋都是非必須的。而xml元素,至少需要一個(gè)成對(duì)標(biāo)簽元素,而且在最外層有且只能有一個(gè),它作為根元素。
從xml元素來(lái)看,分為:
名稱屬性內(nèi)容子節(jié)點(diǎn)
根據(jù)之前的例子,很明顯,名稱是必須要有的而且是唯一的,其他內(nèi)容則是可選。根據(jù)元素的結(jié)束形式,我們把他們分為單標(biāo)簽和雙標(biāo)簽元素。
代碼實(shí)現(xiàn)
完整代碼倉(cāng)庫(kù):xml-parser
實(shí)現(xiàn)存儲(chǔ)解析數(shù)據(jù)的類Element
代碼如下:
namespacexml
usingstd::vector;
usingstd::map;
usingstd::string_view;
usingstd::string;
classElement
public:
usingchildren_t=vectorElement
usingattrs_t=mapstring,string
usingiterator=vectorElement::iterator;
usingconst_iterator=vectorElement::const_iterator;
stringName()
returnm_name;
stringText()
returnm_text;
//迭代器方便遍歷子節(jié)點(diǎn)
iteratorbegin()
returnm_children.begin();
[[nodiscard]]const_iteratorbegin()const
returnm_children.begin();
iteratorend()
returnm_children.end();
[[nodiscard]]const_iteratorend()const
returnm_children.end();
voidpush_back(Elementconstelement)//方便子節(jié)點(diǎn)的存入
m_children.push_back(element);
stringoperator[](stringconstkey)//方便key-value的存取
returnm_attrs[key];
stringto_string()
return_to_string();
private:
string_to_string();
private:
stringm_name;
stringm_text;
children_tm_children;
attrs_tm_attrs;
上述代碼,我們主要看成員變量。
我們用string類型表示元素的name和text用vector嵌套表示孩子節(jié)點(diǎn)用map表示key-value對(duì)的屬性
其余的方法要么是Getter/Setter,要么是方便操作孩子節(jié)點(diǎn)和屬性。當(dāng)然還有一個(gè)to_string()方法這個(gè)待會(huì)講。
關(guān)鍵代碼1實(shí)現(xiàn)整體的解析
關(guān)于整體結(jié)構(gòu)我們分解為下面的情形:
代碼如下:
Elementxml::Parser::Parse()
while(true)
chart=_get_next_token();
if(t!='')
THROW_ERROR("invalidformat",m_str.substr(m_idx,detail_len));
//解析版本號(hào)
if(m_idx+4m_str.size()m_pare(m_idx,5,"xml")==0)
if(!_parse_version())
THROW_ERROR("versionparseerror",m_str.substr(m_idx,detail_len));
continue;
//解析注釋
if(m_idx+3m_str.size()m_pare(m_idx,4,"!--")==0)
if(!_parse_comment())
THROW_ERROR("commentparseerror",m_str.substr(m_idx,detail_len));
continue;
//解析element
if(m_idx+1m_str.size()(isalpha(m_str[m_idx+1])||m_str[m_idx+1]=='_'))
return_parse_element();
//出現(xiàn)未定義情況直接拋出異常
THROW_ERROR("errorformat",m_str.substr(m_idx,detail_len));
上述代碼我們用while循環(huán)進(jìn)行嵌套的原因在于注釋可能有多個(gè)。
關(guān)鍵代碼2解析所有元素
對(duì)應(yīng)代碼:
Elementxml::Parser::_parse_element()
Elementelement;
autopre_pos=++m_idx;//過(guò)掉
//判斷name首字符合法性
if(!(m_idxm_str.size()(std::isalpha(m_str[m_idx])||m_str[m_idx]=='_')))
THROW_ERROR("erroroccurinparsename",m_str.substr(m_idx,detail_len));
//解析name
while(m_idxm_str.size()(isalpha(m_str[m_idx])||m_str[m_idx]==':'||
m_str[m_idx]=='-'||m_str[m_idx]=='_'||m_str[m_idx]=='.'))
m_idx++;
if(m_idx=m_str.size())
THROW_ERROR("erroroccurinparsename",m_str.substr(m_idx,detail_len));
element.Name()=m_str.substr(pre_pos,m_idx-pre_pos);
//正式解析內(nèi)部
while(m_idxm_str.size())
chartoken=_get_next_token();
if(token=='/')//1.單元素,直接解析后結(jié)束
if(m_str[m_idx+1]=='')
m_idx+=2;
returnelement;
}else
THROW_ERROR("parsesingle_elementfailed",m_str.substr(m_idx,detail_len));
if(token=='')//2.對(duì)應(yīng)三種情況:結(jié)束符、注釋、下個(gè)子節(jié)點(diǎn)
//結(jié)束符
if(m_str[m_idx+1]=='/')
if(m_pare(m_idx+2,element.Name().size(),element.Name())!=0)
THROW_ERROR("parseendtagerror",m_str.substr(m_idx,detail_len));
m_idx+=2+element.Name().size();
charx=_get_next_token();
if(x!='')
THROW_ERROR("parseendtagerror",m_str.substr(m_idx,detail_len));
m_idx++;//千萬(wàn)注意把''過(guò)掉,防止下次解析被識(shí)別為初始的tag結(jié)束,實(shí)際上這個(gè)element已經(jīng)解析完成
returnelement;
//是注釋的情況
if(m_idx+3m_str.size()m_pare(m_idx,4,"!--")==0)
if(!_parse_comment())
THROW_ERROR("parsecommenterror",m_str.substr(m_idx,detail_len));
continue;
//其余情況可能是注釋或子元素,直接調(diào)用parse進(jìn)行解析得到即可
element.push_back(Parse());
continue;
if(token=='')//3.對(duì)應(yīng)兩種情況:該標(biāo)簽的text內(nèi)容,下個(gè)標(biāo)簽的開(kāi)始或者注釋(直接continue跳到到下次循環(huán)即可
m_idx++;
//判斷下個(gè)token是否為text,如果不是則continue
charx=_get_next_token();
if(x=='')//不可能是結(jié)束符,因?yàn)閤ml元素不能為空body,如果直接出現(xiàn)這種情況也有可能是中間夾雜了注釋
continue;
//解析text再解析child
autopos=m_str.find('',m_idx);
if(pos==string::npos)
THROW_ERROR("parsetexterror",m_str.substr(m_idx,detail_len));
element.Text()=m_str.substr(m_idx,pos-m_idx);
m_idx=pos;
//注意:有可能直接碰上結(jié)束符,所以需要continue,讓element里的邏輯來(lái)進(jìn)行判斷
continue;
//4.其余情況都為屬性的解析
autokey=_parse_attr_key();
autox=_get_next_token();
if(x!='=')
THROW_ERROR("parseattrserror",m_str.substr(m_idx,detail_len));
m_idx++;
autovalue=_parse_attr_value();
element[key]=value;
THROW_ERROR("parseelementerror",m_str.substr(m_idx,detail_len));
開(kāi)發(fā)技巧
無(wú)論是C++開(kāi)發(fā),還是各種其他語(yǔ)言的造輪子,在這個(gè)造輪子的過(guò)程中,不可能是一帆風(fēng)順的,需要不斷的debug,然后再測(cè)試,然后再debug。。。實(shí)際上這類格式的解析,單純的進(jìn)行程序的調(diào)試效率是非常低下的!
特別是你用的語(yǔ)言還是C++,那么如果出現(xiàn)意外宕機(jī)行為,debug幾乎是不可能簡(jiǎn)單的找出原因的,所以為了方便調(diào)試,或者是意外宕機(jī)行為,我們還是多做一些錯(cuò)誤、
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 注塑車間員工管理制度
- 煙葉育苗設(shè)施管理制度
- 財(cái)務(wù)款付款管理制度
- 生產(chǎn)準(zhǔn)備站管理制度
- 藥品管理部2025年庫(kù)存控制計(jì)劃
- 購(gòu)房人信息公示協(xié)議
- 2025-2030年專用肥公司技術(shù)改造及擴(kuò)產(chǎn)項(xiàng)目可行性研究報(bào)告
- 汽車爆胎處理及修復(fù)協(xié)議
- 新興電商平臺(tái)合作協(xié)議
- 2025-2030金飾行業(yè)市場(chǎng)深度調(diào)研及供需格局與投資前景研究報(bào)告
- 數(shù)字人民幣專題分析
- RITTAL威圖空調(diào)中文說(shuō)明書(shū)
- 馬工程教育學(xué)項(xiàng)賢明第九章-教師與學(xué)生
- 精選最近九年北京高考數(shù)學(xué)(理)壓軸題(含答案)
- XX市救護(hù)車管理辦法
- GB/T 13460-2008再生橡膠
- 中小學(xué)學(xué)習(xí)《民法典》主題班會(huì)圖文ppt
- 簡(jiǎn)明新疆地方史趙陽(yáng)
- 12.注漿法施工技術(shù)(PPT版共60)
- TCVN-2622-越南建筑防火規(guī)范(中文版)
- 拖欠工資起訴狀模版
評(píng)論
0/150
提交評(píng)論