Xerces-c库的使用

Xerces-c是Apache出的一个解析库,功能很强大,但是对用户非常不友好,文档没示例,API REFERENCES没检索的,我还要通过字母分类找,而且API一点都不C++,感觉有点像Java,最后还是按照自己的需求想法做个小demo吧,可以让自己熟悉以下API

这次是做一个解析xml得到数据的小例子,先上数据和代码吧

xml文件 test.xml

<?xml version="1.0" encoding="utf-8"?>
<Students>
    <Student>
        <Name>Marco</Name>
        <Age>19</Age>
        <Sex></Sex>
    </Student>
    <Student>
        <Name>Mary</Name>
        <Age>20</Age>
        <Sex></Sex>
    </Student>
    <Student>
        <Name>Jack</Name>
        <Age>21</Age>
        <Sex></Sex>
    </Student>
</Students>
#include <iostream>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/sax/SAXException.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include <string>
#include <vector>

using namespace std;
using namespace xercesc;

#define STUDENTS_TAG  "Students"
#define STUDENT_TAG   "Student"
#define NAME_TAG      "Name"
#define AGE_TAG       "Age"
#define SEX_TAG       "Sex"

struct Student {
    string  Name;
    int     Age;
    string  Sex;
};

enum ErrorCode
{
    LACK_BEGIN = 1,     // 缺少<Students>标记
    LACK_NAME  = 2,     // 缺少姓名
    LACK_AGE   = 3,     // 缺少年龄
    LACK_SEX   = 4      // 缺少性别
};

DOMElement* findStudentsTag(DOMElement* root)
{
    if (root == 0)
        return 0;
    if (XMLString::compareString(XMLString::transcode(root->getTagName()),STUDENTS_TAG) == 0)
        return root;
    else
        return findStudentsTag(root->getNextElementSibling());
}

int visitDom2GetStudents(DOMElement* root,vector<Student>& students)
{
    DOMElement* stustag = findStudentsTag(root);
    if (stustag == 0)
        return LACK_BEGIN;
    DOMNodeList* stulist = root->getElementsByTagName(XMLString::transcode(STUDENT_TAG));
    size_t length = stulist->getLength();
    for (size_t index = 0; index < length; ++index)
    {
        DOMElement* elems = dynamic_cast<DOMElement*>(stulist->item(index));
        DOMElement* name = elems->getFirstElementChild();
        Student stu;
        if (name == 0)
            return LACK_NAME;
        if (XMLString::compareString(XMLString::transcode(name->getTagName()),NAME_TAG) == 0)
        {
            DOMNode* n = dynamic_cast<DOMNode*>(name);
            stu.Name = static_cast<string>(XMLString::transcode(n->getTextContent()));
        }
        else
            return LACK_NAME;

        DOMElement* age = name->getNextElementSibling();
        if (age == 0)
            return LACK_AGE;
        if (XMLString::compareString(XMLString::transcode(age->getTagName()),AGE_TAG) == 0)
        {
            DOMNode* n = dynamic_cast<DOMNode*>(age);
            stu.Age = atoi(XMLString::transcode(n->getTextContent()));
        }
        else
            return LACK_AGE;
        DOMElement* sex = age->getNextElementSibling();
        if (sex == 0)
        {
            return LACK_SEX;
        }
        if (XMLString::compareString(XMLString::transcode(sex->getTagName()),SEX_TAG) == 0)
        {
            DOMNode* n = dynamic_cast<DOMNode*>(sex);
            stu.Sex = static_cast<string>(XMLString::transcode(n->getTextContent()));
        }
        else
            return LACK_SEX;
        students.emplace_back(stu);
    }
    return 0;
}

int main()
{
    try 
    {
        XMLPlatformUtils::Initialize();
    }
    catch (const XMLException& toCatch)
    {
        std::cerr << XMLString::transcode(toCatch.getMessage());
        return -1;
    }

    XercesDOMParser* parser = new XercesDOMParser();
    ErrorHandler* errHandler = new HandlerBase();
    parser->setErrorHandler(errHandler);
    try
    {
        parser->parse("test.xml");
    }
    catch (const XMLException& toCatch)
    {
        std::cerr << XMLString::transcode(toCatch.getMessage());
        return -1;
    }
    catch (const DOMException& toCatch)
    {
        std::cerr << XMLString::transcode(toCatch.getMessage());
        return -1;
    }
    catch (const SAXException& toCatch)
    {
        std::cerr << XMLString::transcode(toCatch.getMessage());
        return -1;
    }

    DOMDocument* doc = parser->getDocument();
    DOMElement* root = doc->getDocumentElement();
    vector<Student> students;
    int ret = visitDom2GetStudents(root,students);
    if (ret != 0)
        std::cerr << "Parse error\n";
    else
    {
        for (auto stu :students)
        {
            std::cout << "Name: " << stu.Name << "\n"
                  << " Age: " << stu.Age  << "\n"
                  << " Sex: " << stu.Sex  << "\n";
        }
    }
    doc->release();
    XMLPlatformUtils::Terminate();
    return 0;
}

示例简单,这里的errorHandler最好必须带上,因为它能检查你xml文件的正确性,如果不合法就抛出异常,说实话我现在也只感觉到它的作用就是这个,像go能直接把数据绑定到自定义类型里去,哈哈,
然后通过DOMNode和DOMElement得到数据,有人会问,我为什么会把它们两转来转去,这是因为DOMNode是DOMElement的基类,DOMNode和DOMElement的表示范围不同,DOMNode是表示xml任何的合法数据,包括19标签里的数据19,也就是说Age为DOMNode对象时,下个兄弟是19,而Age为DOMElement对象时下个兄弟就为空了(如果这标签是最后一行的话).好拉,知识就这么多了,不懂只能翻API手册了,附上CMakeLists.txt

project(test)
cmake_minimum_required(VERSION 3.5.1)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")


INCLUDE_DIRECTORIES("/home/marco/xerces/include")

LINK_DIRECTORIES("/home/marco/xerces/lib")

ADD_EXECUTABLE(marco "main.cpp")
TARGET_LINK_LIBRARIES(marco xerces-c)

猜你喜欢

转载自blog.csdn.net/RGBMarco/article/details/81253563