XML是一种常见且常用的文档格式。当然,Qt自然也囊括了解析XML相关的模块和类。为了方便以后自己或其他人遇到相关问题时查阅,下面将Qt中解析XML的常见方式罗列出来。
如果不使用第三方的解析库的话,需要在qt的项目文件中加入Qt += xml
Qt中解析XML的方法
1 | 使用Qt的内置XML模块 | QDomDocument,这个模块提供了一种解析和操作XML文档的方式,可用于读取和操作XML文档。可以使用QDomDocument类来解析XML文档,并使用其他相关类来遍历和操作XML树结构,例如QDomNode、QDomElement和QDomText等。 |
2 | QXmlStreamReader QXmlStreamWriter | StreamReader,这个模块提供了一种使用流式方式来解析XML文档的方式。可以使用QXmlStreamReader类来读取XML文档,并根据读取到的事件来处理XML文档中的内容。 |
3 | 使用第三方库 | 如TinyXML、PugiXML等。 |
如果XML文档很大,DOM树最终可能会保留大量内存,对于这样的文档QXmlStreamReader可能是更好的解决方案。本文并不讨论使用第三方库的情况。
以下是一个简单的XML文档示例:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="fiction">
<title lang="en">Harry Potter</title>
<author>J.K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="non-fiction">
<title lang="en">The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<year>1925</year>
<price>19.99</price>
</book>
</bookstore>
接下来就使用Qt中的两种方式来分别读取和生成这个简单的XML文档。
方式1(使用Qt的内置XML模块)
解析XML文档
void xmltest::readXML_dom(){
QFile xmlFile("xml路径.xml");
if(!xmlFile.exists()){
qDebug()<<"文档不存在:"<<xmlFile.fileName();
return;
}
if(!xmlFile.open(QIODevice::ReadOnly)){
qDebug()<<"文档打开失败:"<<xmlFile.fileName();
return;
}
QString errorStr;
int errorLine,errorColumn;
QDomDocument dom;
bool canSet=dom.setContent(&xmlFile,&errorStr,&errorLine,&errorColumn);
if(!canSet){
xmlFile.close();
qDebug()<<"errorStr:"<<errorStr<<"errorLine:"<<errorLine<<"errorColumn:"<<errorColumn;
return;
}
xmlFile.close();
QDomElement bookStoreEle=dom.documentElement();
QString bookStore=bookStoreEle.tagName();
qDebug()<<bookStore;
QDomNode bookNode=bookStoreEle.firstChild();
while(!bookNode.isNull()){
QDomElement bookEle=bookNode.toElement();
if(!bookEle.isNull()){
QString tagName=bookEle.tagName();
QDomAttr attr=bookEle.attributeNode("category");
QString attrStr=attr.value();
qDebug()<<"tagName:"+tagName<<"category:"+attrStr;
QDomNode bookInfoNode=bookEle.firstChild();
while(!bookInfoNode.isNull()){
QString bookNodeName=bookInfoNode.nodeName();
QString bookNodeContent=bookInfoNode.toElement().text();
if(bookInfoNode.hasAttributes()){
qDebug()<<bookInfoNode.attributes().namedItem("lang").nodeValue();
}
qDebug()<<bookNodeName<<bookNodeContent;
bookInfoNode=bookInfoNode.nextSibling();
}
}
bookNode=bookNode.nextSibling();
}
}
执行结果:
"bookstore"
"tagName:book" "category:fiction"
"en"
"title" "Harry Potter"
"author" "J.K. Rowling"
"year" "2005"
"price" "29.99"
"tagName:book" "category:non-fiction"
"en"
"title" "The Great Gatsby"
"author" "F. Scott Fitzgerald"
"year" "1925"
"price" "19.99"
生成XML文档
void xmltest::writeXML_dom(){
QDomDocument doc;
QDomProcessingInstruction xmlDeclaration = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
doc.appendChild(xmlDeclaration);
QDomElement bookStoreEle=doc.createElement("bookstore");
QDomElement bookEle1=doc.createElement("book");
bookEle1.setAttribute("category","fiction");
QDomElement titleEle1=doc.createElement("title");
titleEle1.setAttribute("lang","en");
QDomText titleText1=doc.createTextNode("Harry Potter");
titleEle1.appendChild(titleText1);
QDomElement authorEle1=doc.createElement("author");
QDomText authorText1=doc.createTextNode("J.K. Rowling");
authorEle1.appendChild(authorText1);
QDomElement yearEle1=doc.createElement("year");
QDomText yearText1=doc.createTextNode("2005");
yearEle1.appendChild(yearText1);
QDomElement priceEle1=doc.createElement("price");
QDomText priceText1=doc.createTextNode("29.99");
priceEle1.appendChild(priceText1);
bookEle1.appendChild(titleEle1);
bookEle1.appendChild(authorEle1);
bookEle1.appendChild(yearEle1);
bookEle1.appendChild(priceEle1);
//QDomElement bookEle2; //这种方式是不行的。
//bookEle2.setTagName("book");
//bookStoreEle.appendChild(bookEle2);
QDomElement bookEle2=doc.createElement("book");
bookEle2.setAttribute("category","non-fiction");
QDomElement titleEle2=doc.createElement("title");
titleEle2.setAttribute("lang","en");
QDomText titleText2=doc.createTextNode("The Great Gatsby");
titleEle2.appendChild(titleText2);
QDomElement authorEle2=doc.createElement("author");
QDomText authorText2=doc.createTextNode("F. Scott Fitzgerald");
authorEle2.appendChild(authorText2);
QDomElement yearEle2=doc.createElement("year");
QDomText yearText2=doc.createTextNode("1925");
yearEle2.appendChild(yearText2);
QDomElement priceEle2=doc.createElement("price");
QDomText priceText2=doc.createTextNode("19.99");
priceEle2.appendChild(priceText2);
bookEle2.appendChild(titleEle2);
bookEle2.appendChild(authorEle2);
bookEle2.appendChild(yearEle2);
bookEle2.appendChild(priceEle2);
bookStoreEle.appendChild(bookEle1);
bookStoreEle.appendChild(bookEle2);
doc.appendChild(bookStoreEle);
QFile xmlFile("xml路径.xml");
if(!xmlFile.open(QIODevice::WriteOnly | QIODevice::Text)){
qDebug() << "打开文件失败.";
return;
}
QTextStream stream(&xmlFile);
doc.save(stream, 4); // 4 表示缩进的空格数量
xmlFile.close();
}
这只是简单的示例,QDomDocument、QDomNode、QDomElement提供了丰富的接口可供使用。
方式2(QXmlStreamReader和QXmlStreamWriter)
解析XML文档
void xmltest::readXML_stream(){
QFile xmlFile("xml路径.xml");
if(!xmlFile.exists()){
qDebug()<<"文档不存在:"<<xmlFile.fileName();
return;
}
if(!xmlFile.open(QIODevice::ReadOnly)){
qDebug()<<"文档打开失败:"<<xmlFile.fileName();
return;
}
QXmlStreamReader xmlReader(&xmlFile);
while(!xmlReader.atEnd()&&!xmlReader.hasError()){
QXmlStreamReader::TokenType token=xmlReader.readNext();
if(token==QXmlStreamReader::StartDocument){
qDebug() << "Start Document";
}else if(token==QXmlStreamReader::StartElement){
qDebug() << "Start Element: " << xmlReader.name().toString();
// 处理不同的元素
if (xmlReader.name().toString() == "book") {
qDebug() << "Category: " << xmlReader.attributes().value("category").toString();
} else if (xmlReader.name().toString() == "title") {
qDebug() << "Title: " << xmlReader.readElementText();
} else if (xmlReader.name().toString() == "author") {
qDebug() << "Author: " << xmlReader.readElementText();
} else if (xmlReader.name().toString() == "year") {
qDebug() << "Year: " << xmlReader.readElementText().toInt();
} else if (xmlReader.name().toString() == "price") {
qDebug() << "Price: " << xmlReader.readElementText().toDouble();
}
} else if (token == QXmlStreamReader::EndElement) {
qDebug() << "End Element: " << xmlReader.name().toString();
}
}
if (xmlReader.hasError()) {
qDebug() << "XML Parsing Error: " << xmlReader.errorString();
}
xmlFile.close();
}
运行结果:
Start Document
Start Element: "bookstore"
Start Element: "book"
Category: "fiction"
Start Element: "title"
Title: "Harry Potter"
Start Element: "author"
Author: "J.K. Rowling"
Start Element: "year"
Year: 2005
Start Element: "price"
Price: 29.99
End Element: "book"
Start Element: "book"
Category: "non-fiction"
Start Element: "title"
Title: "The Great Gatsby"
Start Element: "author"
Author: "F. Scott Fitzgerald"
Start Element: "year"
Year: 1925
Start Element: "price"
Price: 19.99
End Element: "book"
End Element: "bookstore"
生成XML文档
void xmltest::writeXML_stream(){
QFile file("xml路径.xml");
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "Failed to open file for writing.";
return;
}
QXmlStreamWriter xmlWriter(&file);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();
xmlWriter.writeStartElement("bookstore");
// 写入第一本书的信息
xmlWriter.writeStartElement("book");
xmlWriter.writeAttribute("category", "fiction");
xmlWriter.writeStartElement("title");
xmlWriter.writeAttribute("lang", "en");
xmlWriter.writeCharacters("Harry Potter");
xmlWriter.writeEndElement(); // title
xmlWriter.writeStartElement("author");
xmlWriter.writeCharacters("J.K. Rowling");
xmlWriter.writeEndElement(); // author
xmlWriter.writeStartElement("year");
xmlWriter.writeCharacters("2005");
xmlWriter.writeEndElement(); // year
xmlWriter.writeStartElement("price");
xmlWriter.writeCharacters("29.99");
xmlWriter.writeEndElement(); // price
xmlWriter.writeEndElement(); // book
// 写入第二本书的信息,类似于第一本书
xmlWriter.writeStartElement("book");
xmlWriter.writeAttribute("category", "non-fiction");
xmlWriter.writeStartElement("title");
xmlWriter.writeAttribute("lang", "en");
xmlWriter.writeCharacters("The Great Gatsby");
xmlWriter.writeEndElement(); // title
xmlWriter.writeStartElement("author");
xmlWriter.writeCharacters("F. Scott Fitzgerald");
xmlWriter.writeEndElement(); // author
xmlWriter.writeStartElement("year");
xmlWriter.writeCharacters("1925");
xmlWriter.writeEndElement(); // year
xmlWriter.writeStartElement("price");
xmlWriter.writeCharacters("19.99");
xmlWriter.writeEndElement(); // price
xmlWriter.writeEndElement(); // book
xmlWriter.writeEndElement(); // bookstore
xmlWriter.writeEndDocument();
file.close();
}
QXmlStreamReader和QXmlStreamWriter也可以与QDomDocument这些内容相结合。
结语
以上示例只是简单的使用了Qt解析XML格式的文档,可以通过Qt官方文档来学习对XML更为细致全面的操作。另外,在Qt5中有QXmlQuery类来支持XPath查询XML文档的内容,Qt6中已经不支持。