简单使用expat

XML不可能比过Json或Yaml的,因为太复杂了。但是有些老旧项目还在使用XML解析器(expat),所以顺便学习了一下。

实验环境,在CentOS操作系统上安装expat开发库:

sudo yum install expat-devel

从 https://libexpat.github.io/doc/getting-started/ 下载

  • elements.c
  • outline.c

编译运行:

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所说,学会4个expat函数,就可以应付80%的场景,接下来我们来体验一下。

(1) 创建一个解析器

XML_Parser parser = XML_ParserCreate(NULL);

(2) 挂钩子函数,处理起始和结束标签

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) 挂钩子函数,处理内容

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) {

举个例子,假设现在有a.xml如下:


111
222
333
444

我们想把它转换成yaml格式,显示在屏幕上,如下:

note:
    aaa: '111'
    bbb: '222'
    ccc: '333'
    ddd: '444'

代码可以是这样的:

#include 
#include 
#include 
#include 
#include 
#include 

struct node {
    size_t depth {0};
    std::string name {""};
    std::string value {""};
};

std::vector 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

你可能感兴趣的:(简单使用expat)