XML不可能比過Json或Yaml的摩窃,因為太復(fù)雜了隆敢。但是有些老舊項目還在使用XML解析器(expat),所以順便學(xué)習(xí)了一下粘姜。
實驗環(huán)境鞠苟,在CentOS操作系統(tǒng)上安裝expat開發(fā)庫:
sudo yum install expat-devel
從 https://libexpat.github.io/doc/getting-started/ 下載
編譯運行:
gcc elements.c && cat a.xml | ./a.out
gcc outline.c && cat a.xml | ./a.out
如https://www.xml.com/pub/a/1999/09/expat/index.html所說乞榨,學(xué)會4個expat函數(shù),就可以應(yīng)付80%的場景当娱,接下來我們來體驗一下吃既。
(1) 創(chuàng)建一個解析器
XML_Parser parser = XML_ParserCreate(NULL);
(2) 掛鉤子函數(shù),處理起始和結(jié)束標(biāo)簽
void startElement(void *userData, const XML_Char *name, const XML_Char **atts) {...}
void endElement(void *userData, const XML_Char *name) {...}
XML_SetElementHandler(parser, startElement, endElement);
(3) 掛鉤子函數(shù)跨细,處理內(nèi)容
void handle_data(void *data, const char *content, int length) {...}
XML_SetCharacterDataHandler(parser, handle_data);
(4) 開始解析
if (XML_Parse(parser, buf, (int)len, done) == XML_STATUS_ERROR) {
舉個例子,假設(shè)現(xiàn)在有a.xml如下:
<note>
<aaa>111</aaa>
<bbb>222</bbb>
<ccc>333</ccc>
<ddd>444</ddd>
</note>
我們想把它轉(zhuǎn)換成yaml格式鹦倚,顯示在屏幕上,如下:
note:
aaa: '111'
bbb: '222'
ccc: '333'
ddd: '444'
代碼可以是這樣的:
#include <fstream>
#include <iostream>
#include <utility>
#include <string>
#include <vector>
#include <expat.h>
struct node {
size_t depth {0};
std::string name {""};
std::string value {""};
};
std::vector<node> root;
node current;
void startElement(void *userData, const XML_Char *name, const XML_Char **atts)
{
int *depthPtr = (int *)userData;
if (current.name.length() != 0)
{
root.push_back(current);
}
current.name = name;
current.depth = *depthPtr;
*depthPtr += 1;
}
void endElement(void *userData, const XML_Char *name)
{
int *depthPtr = (int *)userData;
if (current.name.length() != 0)
{
root.push_back(current);
current.depth = 0;
current.name = "";
current.value = "";
}
*depthPtr -= 1;
}
void handle_data(void *data, const char *content, int length)
{
current.value = content;
current.value.erase(length);
}
void show_data()
{
for (auto e : root)
{
std::cout << std::string(e.depth,' ') << e.name << ":" << e.value << std::endl;
}
}
int main(int argc, const char *argv[])
{
XML_Parser parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, startElement, endElement);
XML_SetCharacterDataHandler(parser, handle_data);
int depth = 0;
XML_SetUserData(parser, &depth);
std::ifstream ifs(argv[1]);
std::string line;
while (std::getline(ifs, line))
{
XML_Parse(parser, line.c_str(), line.length(), 0);
}
XML_ParserFree(parser);
show_data();
return 0;
}
運行:
$ g++ a.c --std=c++11 -lexpat && ./a.out a.xml
note:
aaa:111
bbb:222
ccc:333
ddd:444