1. XML DOM简介
DOM( Document Object Model 文档对象模型) 是一种用来解析 XML 文档的标准应用程序编程接口,它由万维网(W3C)所开发以及所推荐的标准。DOM 定义了所有文档元素的对象和属性,以及访问它们的方法(接口),它把 XML 文件表示成 内存 中的一棵树。使得我们可以按照需要去遍历这个 DOM 树,同时也可以对其进行修改操作,并且将其 作为 XML 文件保存到磁盘中。对于 DOM ,这里有几个重要的概念需要理解和掌握:
(1)XML 文档中的每个成分都是一个节点
DOM 是这样定义的:
①整个文档是一个文档节点
②每个 XML 标签是一个元素节点
③包含在 XML 元素中的文本是文本节点
④每一个 XML 属性是一个属性节点
⑤注释属于注释节点
(2)文本总是存储在文本节点中
在 DOM 处理中一个普遍的错误是,认为元素节点包含文本。其实是元素节点的文本是存储在文本节点中的。
比如:
<age>25</age>,元素节点 <age>,拥有一个值为 "25" 的文本节点。
"25" 不是 <age> 元素的值!
(3)XML DOM 把 XML DOM 文档视为一棵节点树 (node-tree)。树中的所有节点彼此之间都有关系
为了更加深刻的理解上面对 XML DOM的描述,下面将一个 XML 文档 用 DOM 树描述出来,注意它们之间的对应关系。
XML 文档如下:
<?xml version="1.0" encoding="UTF-8"?>
<bookcase>
<book category="computer">
<title lang="en"> GUI Qt</title>
<author>Jasmin Blanchette</author>
<year>2013</year>
<price>75.0</price>
</book>
<book category="database">
<title lang="en">MongoDB</title>
<author>Kristina Chodorow</author>
<year>2017</year>
<price>63.0</price>
</book>
<book category="web" cover="paperback">
<title lang="en">Learning XML</title>
<author>Rick Coperland</author>
<year>2015</year>
<price>42.90</price>
</book>
</bookcase>
对应的 DOM 树:
========== 使用DOM 读取 XML 文件 ==========
2. DOM 解析上面的 XML 文件 代码一
domxmlparse.h文件
#ifndef DOMXMLPARSE_H
#define DOMXMLPARSE_H
#include <QString>
#include <QDebug>
#include <QFile>
#include <QtXml/QDomDocument>
#include <QtXml/QDomElement>
#include <QTXML/QDomNode>
class DomXmlParse
{
public:
DomXmlParse();
~DomXmlParse();
void readDomXmlFile(const QString filePath);
};
#endif // DOMXMLPARSE_H
domxmlparse.cpp 文件
#include "domxmlparse.h"
DomXmlParse::DomXmlParse()
{
}
DomXmlParse::~DomXmlParse()
{
}
/**
* @brief DomXmlParse::readDomXmlFile
* @param filePath
* @return NONE
*/
void DomXmlParse::readDomXmlFile(const QString filePath)
{
if(true == filePath.isEmpty() || 0 == filePath.length())
{
qDebug()<<"Error: filePath is empty .";
return;
}
//以读方式打开XML文件
QFile file(filePath);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug()<<"Error: open filePath failure.";
return;
}
QString errorStr;
int errorLine;
int errorColumn;
QDomDocument doc;
//将XML文件加载到Dom 文档对象模型内存中
if(!doc.setContent(&file,false,&errorStr,&errorLine,&errorColumn))
{
qDebug()<<"Error setContent, errorStr["<<errorStr<<"]"<<"errorLine["<<errorLine<<"]" \
<<"errorColumn["<<errorColumn<<"]";
return;
}
//获取DOM树中的第一个节点元素
QDomElement root = doc.documentElement();
if("bookcase" != root.tagName())
{
qDebug()<<"Error: documentElement ";
return;
}
else
{
QDomNode node = root.firstChild();
while(!node.isNull())
{
if("book" == node.toElement().tagName())
{
QDomNode subNode = node.firstChild();
while(!subNode.isNull())
{
if("title" == subNode.toElement().tagName())
{
QString title = subNode.toElement().text();
qDebug()<<title;
}
if("author" == subNode.toElement().tagName())
{
QString author = subNode.toElement().text();
qDebug()<<author;
}
if("year" == subNode.toElement().tagName())
{
QString year = subNode.toElement().text();
qDebug()<<year;
}
if("price" == subNode.toElement().tagName())
{
QString price = subNode.toElement().text();
qDebug()<<price;
}
subNode = subNode.nextSibling();
}
}
else
{
qDebug()<<"Error: not find subnode.";
}
node = node.nextSibling();
}
}
return;
}
main.cpp 文件
#include "widget.h"
#include "domxmlparse.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
DomXmlParse parseXml;
parseXml.readDomXmlFile("D:\\code\\untitled\\doc\\DomXml02.xml");
return a.exec();
}
编译运行结果:
" GUI Qt"
"Jasmin Blanchette"
"2013"
"75.0"
"MongoDB"
"Kristina Chodorow"
"2017"
"63.0"
"Learning XML"
"Rick Coperland"
"2015"
"42.90"
3. DOM 解析如下XML文件 代码二
<?xml version="1.0" encoding="UTF-8"?>
<sports>
<entry term = "basketball">
<page>10</page>
<page>34-35</page>
<page>307-308</page>
</entry>
<entry term = "football">
<entry term ="A football team">
<page>115</page>
<page>244</page>
</entry>
<entry term = "B football team">
<page>9</page>
</entry>
</entry>
</sports>
说明:其他不改变,只需要修改 readDomXmlFile 函数即可
/**
* @brief DomXmlParse::readDomXmlFile
* @param filePath
* @return NONE
*/
void DomXmlParse::readDomXmlFile(const QString filePath)
{
if(true == filePath.isEmpty() || 0 == filePath.length())
{
qDebug()<<"Error: filePath is empty .";
return;
}
//以读方式打开XML文件
QFile file(filePath);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug()<<"Error: open filePath failure.";
return;
}
QString errorStr;
int errorLine;
int errorColumn;
QDomDocument doc;
//将XML文件加载到Dom 文档对象模型内存中
if(!doc.setContent(&file,false,&errorStr,&errorLine,&errorColumn))
{
qDebug()<<"Error setContent, errorStr["<<errorStr<<"]"<<"errorLine["<<errorLine<<"]" \
<<"errorColumn["<<errorColumn<<"]";
return;
}
//获取DOM树中的第一个节点元素
QDomElement root = doc.documentElement();
if("sports" != root.tagName())
{
qDebug()<<"Error: documentElement ";
return;
}
else
{
QDomNode node = root.firstChild();
while(!node.isNull())
{
if("entry" == node.toElement().tagName())
{
//打印节点元素的属性值
QString attr = node.toElement().attribute("term");
qDebug()<<attr;
QDomNode child = node.toElement().firstChild();
while(!child.isNull())
{
if("page" == child.toElement().tagName())
{
QString page = child.toElement().text();
qDebug()<<page;
}
else if("entry" == child.toElement().tagName())
{
//打印节点元素的属性值
QString attru = child.toElement().attribute("term");
qDebug()<<attru;
QDomNode subChild = child.toElement().firstChild();
while(!subChild.isNull())
{
if("page" == subChild.toElement().tagName())
{
QString page = subChild.toElement().text();
qDebug()<<page;
}
else
{
qDebug()<<"Error: Dom file";
}
subChild = subChild.nextSibling();
}
}
child = child.nextSibling();
}
}
node = node.nextSibling();
}
}
return;
}
编译运行执行结果:
"basketball"
"10"
"34-35"
"307-308"
"football"
"A football team"
"115"
"244"
"B football team"
"9"
========= 使用DOM 生成(写) XML 文件 ========
4. 使 DOM 方式生成(写)代码一中的 XML 文件,该 XML 如下:
<?xml version="1.0" encoding="UTF-8"?>
<bookcase>
<book category="computer">
<title lang="en"> GUI Qt</title>
<author>Jasmin Blanchette</author>
<year>2013</year>
<price>75.0</price>
</book>
<book category="database">
<title lang="en">MongoDB</title>
<author>Kristina Chodorow</author>
<year>2017</year>
<price>63.0</price>
</book>
<book category="web" cover="paperback">
<title lang="en">Learning XML</title>
<author>Rick Coperland</author>
<year>2015</year>
<price>42.90</price>
</book>
</bookcase>
在 DomXmlParse 类中新增加一个成员函数,writeDomXmlFile ,具体代码为:
void DomXmlParse::writeDomXmlFile(const QString filePath)
{
//打开或创建文件
QFile file(filePath); //相对路径、绝对路径、资源路径都可以
if(!file.open(QFile::WriteOnly|QFile::Truncate)) //可以用QIODevice,Truncate表示清空原来的内容
return;
QDomDocument doc;
//写入xml头部
QDomProcessingInstruction instruction; //添加处理命令
//创建XML文档的版本号和编码
instruction=doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");
doc.appendChild(instruction);
//添加根节点
QDomElement root=doc.createElement("bookcase");
doc.appendChild(root);
//添加第一个子节点及其子元素; //方式一:创建属性 其中键值对的值可以是各种类型
QDomElement book=doc.createElement("book");
book.setAttribute("category","computer");
/*//创建节点属性值:方式二:创建属性 值必须是字符串
QDomAttr time=doc.createAttribute("category");
time.setValue("computer");
*/
QDomElement title=doc.createElement("title"); //创建子元素
title.setAttribute("lang","en");
QDomText text; //设置括号标签中间的值
text=doc.createTextNode("GUI Qt");
book.appendChild(title);
title.appendChild(text);
QDomElement author=doc.createElement("author"); //创建子元素
text=doc.createTextNode("Jasmin Blanchette");
author.appendChild(text);
book.appendChild(author);
QDomElement year=doc.createElement("year"); //创建子元素
text=doc.createTextNode("2013");
year.appendChild(text);
book.appendChild(year);
QDomElement price=doc.createElement("price"); //创建子元素
text=doc.createTextNode("Jasmin Blanchette");
price.appendChild(text);
book.appendChild(price);
root.appendChild(book);
//添加第二个子节点及其子元素,部分变量只需重新赋值
book=doc.createElement("book");
book.setAttribute("category","database");
title = doc.createElement("titile");
title.setAttribute("lang","en"); //设置节点属性值
text = doc.createTextNode("MongoDB");
title.appendChild(text);
book.appendChild(title);
author=doc.createElement("author");
text=doc.createTextNode("Kristina Chodorow");
author.appendChild(text);
book.appendChild(author);
year=doc.createElement("year");
text=doc.createTextNode("2017");
year.appendChild(text);
book.appendChild(year);
price=doc.createElement("price");
text=doc.createTextNode("63.0");
price.appendChild(text);
book.appendChild(price);
root.appendChild(book);
//添加第三个节点
book=doc.createElement("book");
book.setAttribute("category","web");
//创建节点属性值:方式二:创建属性 值必须是字符串
QDomAttr cover=doc.createAttribute("cover");
cover.setValue("paperback");
book.setAttributeNode(cover);
title = doc.createElement("titile");
title.setAttribute("lang","en");
text = doc.createTextNode("Learning XML");
title.appendChild(text);
book.appendChild(title);
author=doc.createElement("author");
text=doc.createTextNode("Rick Coperland");
author.appendChild(text);
book.appendChild(author);
year=doc.createElement("year");
text=doc.createTextNode("2015");
year.appendChild(text);
book.appendChild(year);
price=doc.createElement("price");
text=doc.createTextNode("42.90");
price.appendChild(text);
book.appendChild(price);
root.appendChild(book);
//输出到文件
QTextStream out_stream(&file);
doc.save(out_stream,4); //缩进4格
file.close();
return;
}
main.cpp 文件中 main 函数调用方式如下:
#include "widget.h"
#include "domxmlparse.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
DomXmlParse parseXml;
parseXml.writeDomXmlFile("D:\\code\\untitled\\doc\\DomXml03.xml");
return a.exec();
}
编译并运行该代码后,会在该目录下生成一个名为 DomXml03.xml 的文件。
其 DomXml03.xml 文件的内容为: