QXmlStreamReader读取XML
QXmlStreamReader按标签逐行读取XML文件,解析效率高,内存占用小
QXmlStreamReader在SAX解析的基础上,进行了接口简化
但是Qt仍然保留了SAX解析接口,因为SAX解析和DOM解析是两种公认的标准,方便用户从其它语言进行代码迁移
//xml文件
<doc date="2019-12-30">
<item name="A" id="1">
My Name is A
</item>
<item name="B" id="2">
My Name is B
</item>
<item name="C" id="3">
My Name is C
</item>
</doc>
//读取xml文件
QFile file("C:/1.xml");
file.open(QFile::ReadWrite);
reader.setDevice(&file);
QXmlStreamReader reader;
//逐行读取,按类型打印
while (!reader.atEnd()) {
QXmlStreamReader::TokenType type = reader.readNext();
switch (type) {
case QXmlStreamReader::TokenType::StartDocument:
qdebug << "Document Start" << endl;
break;
case QXmlStreamReader::TokenType::EndDocument:
qdebug << "Document End" << endl;
break;
case QXmlStreamReader::TokenType::StartElement:
qdebug << reader.name() << endl;
qdebug << "id=" << reader.attributes().value("id") << endl;
qdebug << "name=" << reader.attributes().value("name") << endl;
break;
case QXmlStreamReader::TokenType::EndElement:
qdebug << reader.name() << endl;
break;
case QXmlStreamReader::TokenType::Characters:
qdebug << reader.text().trimmed() << endl;
break;
default:
break;
}
}
DOM读取XML
DOM解析先整个文档直接读入内存,转化为一个树类型的数据结构对象,再逐个遍历
DOM解析将文档操作转化为数据结构操作,更符合程序员思维,因此易于使用,特别是在一些复杂查找的情景下
但是由于DOM一次性加载整个文档,因此占用内存较大,不适合大型文档
#include "qlib.h"
//递归遍历DOM结点
void parseDomElement(QDomNode node) {
//打印当前结点内容
QDomNode::NodeType type = node.nodeType();
switch (type) {
case QDomNode::NodeType::AttributeNode:
qdebug << node.toAttr().name() << "=" << node.toAttr().value() << endl;
break;
case QDomNode::NodeType::TextNode:
qdebug << node.toText().data().trimmed() << endl;
break;
case QDomNode::NodeType::ElementNode:
qdebug << node.toElement().tagName() << endl;
break;
default:
break;
}
//递归遍历子结点
QDomNodeList childNodeList = node.childNodes();
for (int i = 0; i < childNodeList.size(); i++) parseDomElement(childNodeList.at(i));
//打印结束标签
if (type == QDomNode::NodeType::ElementNode) qdebug << node.toElement().tagName() << endl;
}
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
QMainWindow w;
w.show();
//设置字符编码
setlocale(LC_ALL, ".ACP");
//打开文件
QFile file("C:/1.xml");
file.open(QFile::ReadWrite);
//加载文件内容
QString errorMessage;
int errorLine;
int errorColumn;
QDomDocument doc;
doc.setContent(&file, &errorMessage, &errorLine, &errorColumn);
//解析文档
QDomElement rootElement = doc.documentElement();
parseDomElement(rootElement);
return app.exec();
}
SAX读取XML
SAX逐行逐个元素读取XML,并且由用户手动控制解析流程,SAX解析的接口风格是明显的底层化风格
由于用户可以自己控制解析流程,因此不需要解析无用的数据,因此效率足够高
但是由于接口风格非常底层化,没有经过任何封装简化,所以使用起来代码比较繁琐
在Qt下,推荐使用QXmlStreamReader,它相当于优化版的SAX解析
//设置字符编码
setlocale(LC_ALL, ".ACP");
//打开文件
QFile file("C:/1.xml");
file.open(QFile::ReadWrite);
//XML处理器
class SaxHandler : public QXmlDefaultHandler {
bool startDocument() {
qdebug << "document start" << endl;
return true;
}
bool endDocument() {
qdebug << "document end" << endl;
return true;
}
bool startElement(
const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts) {
qdebug << localName << endl;
for (int i = 0; i < atts.length(); i++) qdebug << atts.qName(i) << atts.value(i) << endl;
return true;
}
bool endElement(const QString& namespaceURI, const QString& localName, const QString& qName) {
qdebug << localName << endl;
return true;
}
bool characters(const QString& ch) {
qdebug << ch.trimmed() << endl;
return true;
}
} handler;
//开始解析
QXmlSimpleReader reader;
reader.setContentHandler(&handler);
reader.parse(QXmlInputSource(&file));
QXmlStreamWriter写入XML
Qt写入XML主要有三种方式
- 手动写入字符串
- 在DOM解析中,修改QDomDocument 后,调用QDomDocument ::save保存修改
- 使用QXmlStreamWriter
第一种只适合极其简单的文档,第二种适合先读再改,第三种适合重新创建一个XML文档
前两种不需要特意讲解,现在来讲使用QXmlStreamWriter来创建写入XML文档
//打开文件
QFile file("C:/2.xml");
file.open(QFile::ReadWrite);
//写入节点
QXmlStreamWriter writer(&file);
writer.setAutoFormatting(true);
writer.writeStartDocument();
writer.writeStartElement("doc");
for (int i = 0; i < 3; i++) {
writer.writeStartElement("item");
writer.writeAttribute("id", "1");
writer.writeAttribute("name", "A");
writer.writeCharacters("This is a Xml Node");
writer.writeEndElement();
}
writer.writeEndElement();
writer.writeEndDocument();
file.close();