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)