版权声明:本文为博主原创文章,未经博主允许不得转载。
一、简介
QtXml模块提供了一个读写XML文件的流,解析方法包含DOM和SAX。DOM(Document ObjectModel):将XML文件表示成一棵树,便于随机访问其中的节点,但消耗内存相对多一些。SAX(Simple APIfor XML):一种事件驱动的XML API,接近于底层,速度较快,但不便于随机访问任意节点。
使用XML模块,在.pro文件中添加QT += xml,并加如相应的头文件#include <QDomDocument>或者#include <QXmlStreamReader>。
分析的xml文件:
- <?xml version="1.0" encoding="UTF-8"?>
- <COMMAND>
- <OBJECT>USER</OBJECT>
- <ACTION>LOGIN</ACTION>
- <DATA>
- <USER NAME="root" PASSWORD="123456"/>
- </DATA>
- </COMMAND>
二、详解
1、QXmlStreamReader
(1)streamparsexml.h
- #ifndef STREAMPARSEXML_H
- #define STREAMPARSEXML_H
- #include <QXmlStreamWriter>
- #include <QXmlStreamReader>
- #include <QFile>
- #include <QMessageBox>
- class StreamParseXml
- {
- public:
- StreamParseXml();
- ~StreamParseXml();
- int writeXml();
- int readXml();
- private:
- void parseUserInformation();
- QString getValue(const QString &name);
- QString getAttribute(const QString &name);
- private:
- QString fileName;
- QXmlStreamReader *reader;
- };
- #endif // STREAMPARSEXML_H
- #include <QDebug>
- #include "streamparsexml.h"
- StreamParseXml::StreamParseXml()
- {
- fileName = "streamparse.xml";
- }
- StreamParseXml::~StreamParseXml()
- {
- }
- int StreamParseXml::writeXml()
- {
- QFile file(fileName);
- if(file.open(QIODevice::WriteOnly | QIODevice::Text)) {
- QXmlStreamWriter writer(&file);
- writer.setAutoFormatting(true);
- writer.writeStartDocument();
- writer.writeStartElement("COMMAND");
- writer.writeTextElement("OBJECT", "USER");
- writer.writeTextElement("ACTION", "LOGIN");
- writer.writeStartElement("DATA");
- writer.writeStartElement("USER");
- writer.writeAttribute("NAME", "root");
- writer.writeAttribute("PASSWORD", "123456");
- writer.writeEndElement();
- writer.writeEndElement();
- writer.writeEndElement();
- file.close();
- }
- return 0;
- }
- int StreamParseXml::readXml()
- {
- if(fileName.isEmpty()) return -2;
- QFile *file = new QFile(fileName);
- if(!file->open(QFile::ReadOnly | QFile::Text)) {
- QMessageBox::information(NULL, QString("title"), QString("open error!"));
- return -1;
- }
- reader = new QXmlStreamReader(file);
- while(!reader->atEnd() && !reader->hasError()) {
- QXmlStreamReader::TokenType token = reader->readNext();
- if(token == QXmlStreamReader::StartDocument) {
- continue;
- }
- if (reader->isStartElement() && reader->name() == "OBJECT") {
- QString elementText = reader->readElementText();
- if (elementText == "USER") {
- parseUserInformation();
- break;
- }
- }
- }
- if (reader->hasError()) {
- qDebug() << reader->errorString();
- //QMessageBox::information(NULL, QString("parseXML"), reader->errorString());
- }
- reader->clear();
- delete reader;
- reader = NULL;
- return 0;
- }
- void StreamParseXml::parseUserInformation()
- {
- QString elementString = getValue("ACTION");
- if (elementString == "LOGIN") {
- while(!reader->atEnd()) {
- reader->readNext();
- if (reader->name() == "USER") {
- QXmlStreamAttributes attributes = reader->attributes();
- if(attributes.hasAttribute("NAME")) {
- qDebug() << "USER=" << attributes.value("NAME").toString();
- }
- if(attributes.hasAttribute("PASSWORD")) {
- qDebug() << "PASSWORD=" << attributes.value("PASSWORD").toString();
- }
- }
- }
- }
- }
- QString StreamParseXml::getValue(const QString &name)
- {
- while(!reader->atEnd()) {
- reader->readNext();
- if (reader->isStartElement() && reader->name() == name) {
- return reader->readElementText();
- }
- }
- return "";
- }
2、QDomDocument
(1)domdocument.h
- #ifndef DOMDOCUMENT_H
- #define DOMDOCUMENT_H
- #include <QDomDocument>
- #include <QFile>
- #include <QTextStream>
- class DomDocument
- {
- public:
- DomDocument();
- ~DomDocument();
- int writeXml();
- int readXml();
- int readXml2();
- private:
- QString fileName;
- };
- #endif // DOMDOCUMENT_H
- #include <QDebug>
- #include "domdocument.h"
- DomDocument::DomDocument()
- {
- fileName = "domparse.xml";
- }
- DomDocument::~DomDocument()
- {
- }
- int DomDocument::writeXml()
- {
- QFile file(fileName);
- if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
- return -2;
- QTextStream out(&file);
- QDomDocument doc;
- QDomText text;
- QDomElement element;
- QDomAttr attr;
- QDomProcessingInstruction instruction;
- instruction = doc.createProcessingInstruction( "xml", "version = \'1.0\' encoding=\'UTF-8\'" );
- doc.appendChild( instruction );
- QDomElement root = doc.createElement( "COMMAND" );
- doc.appendChild(root);
- element = doc.createElement( "OBJECT" );
- text = doc.createTextNode( "USER" );
- element.appendChild(text);
- root.appendChild(element);
- element = doc.createElement( "ACTION" );
- text = doc.createTextNode( "LOGIN" );
- element.appendChild(text);
- root.appendChild(element);
- element = doc.createElement( "DATA" );
- root.appendChild(element);
- QDomElement userElement = doc.createElement( "USERINFO" );
- attr = doc.createAttribute( "NAME" );
- attr.setValue("root");
- userElement.setAttributeNode(attr);
- attr = doc.createAttribute( "PASSWORD" );
- attr.setValue("123456");
- userElement.setAttributeNode(attr);
- element.appendChild(userElement);
- doc.save(out, 4); //each line space of file is 4
- return 0;
- }
- int DomDocument::readXml()
- {
- QDomDocument doc;
- QFile file(fileName);
- QString error = "";
- int row = 0, column = 0;
- if (!file.open(QIODevice::ReadOnly)) return -2;
- if(!doc.setContent(&file, false, &error, &row, &column)){
- qDebug() << "parse file failed:" << row << "---" << column <<":" <<error;
- file.close();
- return -1;
- }
- file.close();
- QDomElement root = doc.documentElement();
- QDomNode node = root.firstChild();
- while(!node.isNull()) {
- QDomElement element = node.toElement(); // try to convert the node to an element.
- if(!element.isNull()) {
- qDebug()<<element.tagName() << ":" << element.text();
- QDomNode nodeson = element.firstChild();
- while(!nodeson.isNull()) {
- QDomElement elementson = nodeson.toElement();
- if(!elementson.isNull()) {
- qDebug()<< "---" <<elementson.tagName();
- if (elementson.hasAttribute("NAME")) {
- qDebug()<< "---" << "NAME=" << elementson.attributeNode("NAME").value();
- }
- if (elementson.hasAttribute("PASSWORD")) {
- qDebug()<< "---" << "PASSWORD=" << elementson.attributeNode("PASSWORD").value();
- }
- }
- nodeson = nodeson.nextSibling();
- }
- }
- node = node.nextSibling();
- }
- return 0;
- }
- int DomDocument::readXml2()
- {
- QDomDocument doc;
- QFile file(fileName);
- QString error = "";
- int row = 0, column = 0;
- if (!file.open(QIODevice::ReadOnly)) return -2;
- if(!doc.setContent(&file, false, &error, &row, &column)){
- qDebug() << "parse file failed:" << row << "---" << column <<":" <<error;
- file.close();
- return -1;
- }
- file.close();
- QDomElement root = doc.documentElement();
- QDomNode node = root.firstChildElement();
- while(!node.isNull()) {
- QDomElement element = node.toElement(); // try to convert the node to an element.
- if(!element.isNull()) {
- if (element.tagName() == "DATA") {
- qDebug()<< "---" <<element.tagName();
- QDomNodeList list = element.childNodes();
- for(int index = 0; index < list.count(); index++) {
- QDomNode list_node = list.item(index);
- QDomElement list_element = list_node.toElement();
- if (list_element.hasAttribute("NAME")) {
- qDebug()<< "---" << "NAME =" << list_element.attributeNode("NAME").value();
- }
- if (list_element.hasAttribute("PASSWORD")) {
- qDebug()<< "---" << "PASSWORD =" << list_element.attributeNode("PASSWORD").value();
- }
- }
- }
- else {
- qDebug()<<element.tagName() << ":" << element.text();
- }
- }
- node = node.nextSibling();
- }
- return 0;
- }
- #include <QCoreApplication>
- #include <QDebug>
- #include "streamparsexml.h"
- #include "domdocument.h"
- int main(int argc, char *argv[])
- {
- QCoreApplication a(argc, argv);
- // StreamParseXml stream;
- // stream.writeXml();
- // stream.readXml();
- DomDocument dom;
- dom.writeXml();
- dom.readXml();
- qDebug() << "***********************";
- dom.readXml2();
- return a.exec();
- }
(4)运行
3、其他XML解析库
常见C/C++ XML解析器有tinyxml、XERCES、squashxml、xmlite、pugxml、libxml等等,这些解析器有些是支持多语言的,有些只是单纯C/C++的。
(1)Xerces XML解析器
官方网址:http://xerces.apache.org/xerces-c/
Xerces前身是IBM的XML4C,XML4C也是一种功能强大的XML解析器,之后交给Apache基金会管理,遂改名为Xerces,Xerces-C++让你的程序提供读写XML数据更加容易,提供的共享库通过DOM、SAX、SAX2 API等方式对XML文档进行解析、生成、操作和验证。
Xerces-C++忠实于XML 1.0建议和相关标准。
Xerces-C++解析器高性能、模块化并且可扩展。相关开发资料也比较完善。
除了C++版本,Xerces同时还提供Xerces Java,Xerces Perl等版本。
(2)TinyXML解析器
官方网址:http://www.grinninglizard.com/tinyxml/
TinyXML相比Xerces要功能简单些,正如其名Tiny,使用方法也比较简单,TinyXML也是一个开源的解析XML解析库,用于C++,支持Windows和Linux。TinyXML通过DOM模型遍历和分析XML。官方文档:
http://www.grinninglizard.com/tinyxmldocs/index.html
(3)squashXML解析器
官方地址:http://ostatic.com/squashxml
这个解析器在国内似乎少人使用,这个解析器也有些历史了。squashXML基于DOM Level2,也是一个XML轻量级的解析器。天缘之所以把这个写上是天缘比较看重这个解析器的目录划分及使用说明,易懂而且易上手。
(4)XMLBooster解析器
官方网址:http://www.xmlbooster.com/
XMLBooster开发关注点比较有特色,更加关注解析性能,声称:“Application integration of XML data cannot get any simpler or any faster: instead of dealing with sophisticated api (such as DOM or SAX), use a convenient data structure, generated to suit your specific purpose, in the language of your choice. ”。
针对特殊需求使用更加方便的数据结构以提高性能。
(5)LibXML解析器
官方地址:http://xmlsoft.org/
LibXML本来是为Gnome项目开发(C开发),之后被广泛使用,功能非常强大,几乎适合于常见的所有操作系统下编译和开发使用。libxml++(地址:http://libxmlplusplus.sourceforge.net/)是对libxml XML解析器的C++封装版本。此外还有各种语言封装包,参考官方链接。
(6)补充:
除了上述XML解析库外,还有一些XML解析器(参考:http://www.garshol.priv.no/xmltools/platform/cpp.html),比如Berkely DBXML(BDB)等,有兴趣的读者可自行Google搜索。
尽管XML解析器有很多种,而且功能差异很大,甚至是支持跨平台、多语言,但是对于你的应用而言,尽量选择一种相对熟悉、功能够用的即可,没必要去追求庞杂的解析器,我们只需关注:功能够用、相对稳定、适合扩展这三个功能即可。一旦有问题,修正和扩展都要更为容易。
四、总结
(1)注意:readElementText()函数在解析出开始标签时,就可以解析元素的文本了,直到遇到结束标签。readElementText()函数中好像有类似于readNext()这样的函数读取下一个元素并比较是否为endElement,所以当使用readElementText()读取完元素文本时,该元素的闭合标签已经被读走了。(2)QDomProcessingInstruction instruction;instruction = doc.createProcessingInstruction("xml","version=/"1.0/" encoding=/"UTF-8/"");用来写入XML文件的声明,这对于一个XML文件来说不可缺少。
转自:http://blog.csdn.net/taiyang1987912/article/details/46695245