最近使用Qt开发软件,需要用到xml用于保存软件配置信息,发现Qt的XML使用起来不是很方便,所以基于QDomDocument类进一步封装了QXmlWrapper类。
注:博主用的Qt版本是4.8.5,开发环境是Qt Creator。
一、XML文件的创建、删除与重命名
1.XML文件的创建
bool QXmlWrapper::CreateXmlFile(const QString &_fileName, const QString &_rootName, const QString &_version, const QString &_encoding, const QString &_standalone) { QFile file(_fileName); // 只写方式打开,并清空以前的信息 if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) return false; QDomDocument doc; QDomProcessingInstruction instruction; //添加处理指令(声明) QString data; data = "version=\"" + _version + "\" encoding=\"" + _encoding + "\" standalone=\"" + _standalone + "\""; instruction = doc.createProcessingInstruction("xml", data); doc.appendChild(instruction); QDomElement root = doc.createElement(_rootName); doc.appendChild(root); //添加根元素 QTextStream out(&file); doc.save(out,4); // 将文档保存到文件,4为子元素缩进字符数 file.close(); return true; }
其中_fileName为文件名,_rootName为根节点名。
2.XML文件的删除
bool QXmlWrapper::DeleteXmlFile(const QString &_fileName)
{
if (_fileName.isEmpty())
{
return false;
}
QFile file(_fileName);
if(!file.setPermissions(QFile::WriteOwner)) // 修改文件属性
return false;
if(!QFile::remove(_fileName)) // 删除文件
return false;
return true;
}
若文件为只读属性,需要修改文件属性。
3.XML文件的重命名
bool QXmlWrapper::RenameXmlFile(const QString &_fileName,
const QString &_newName)
{
return QFile::rename(_fileName, _newName);
}
二、元素节点的操作
无论查询节点、删除节点、修改节点和增加节点,其实都离不开一个函数,就是根据节点名获取相关节点。那么我们就先实现一个根据节点名获取节点的函数:
1.根据节点名获取节点
bool QXmlWrapper::GetNodeByName(QDomElement &_rootEle,
const QString &_nodeName,
QDomElement &_node)
{
if(_nodeName == _rootEle.tagName()) // 若为根节点,则返回
{
_node = _rootEle;
return true;
}
QDomElement ele = _rootEle; //返回根元素
for (ele = _rootEle.firstChildElement(); ele.isElement(); ele = ele.nextSiblingElement())
{
//递归处理子节点,获取节点
if(GetNodeByName(ele, _nodeName, _node))
return true;
}
return false;
}
其中,_rootEle为根节点,_nodeName为待查询的节点名,_node即为查找到的节点。
首先,根据节点名判断是否为根节点,若是则返回true,若不是则查询所有子节点是否符合条件;
然后,若还未查到则递归查询,直到满足为止。
若所有节点都不符合条件,则返回false。
2.新增元素节点
这里分2种情况:有文本无属性的节点、既有文本又有属性的节点。
先说第一种,有文本无属性的节点:
首先根据XML文件名读取文件内容并存入QDomDocument对象Doc;
然后根据Doc获取根节点QDomElement rootEle = doc.documentElement();
再利用上面的提到的GetNodeByName获取该节点的父节点;
最后利用QDomElement的appChild方法插入该子节点。
bool QXmlWrapper::AddNode_Text(const QString &_fileName,
const QString &_parentNodeName,
const QString &_nodeName,
const QString &_nodeText)
{
if (_fileName.isEmpty()) // 文件名为空
{
return false;
}
// 新建QDomDocument类对象,它代表一个XML文档
QDomDocument doc;
// 建立指向“_fileName”文件的QFile对象
QFile file(_fileName);
// 以只读方式打开
if (!file.open(QIODevice::ReadOnly))
return false;
// 将文件内容读到doc中
if (!doc.setContent(&file))
{
file.close();
return false;
}
// 关闭文件
file.close();
QDomElement rootEle = doc.documentElement(); //返回根元素
QDomElement parentNode;
GetNodeByName(rootEle, _parentNodeName, parentNode);
// 添加元素及其文本
QDomElement childEle = doc.createElement(_nodeName);
QDomText text;
text = doc.createTextNode(_nodeText);
childEle.appendChild(text);
parentNode.appendChild(childEle);
if(!file.open(QFile::WriteOnly|QFile::Truncate)) //先读进来,再重写,如果不用truncate就是在后面追加内容,就无效了
return false;
//输出到文件
QTextStream out(&file);
doc.save(out,4); // 将文档保存到文件,4为子元素缩进字符数
file.close();
return true;
}
3.删除元素节点
与新增元素节点类似,只是查找的不是父节点而是该节点本身,最后利用QDomElement的removeChild()方法删除该节点。
// 假如是根节点
if (rootEle == nodeEle)
//doc.removeChild(rootEle);
return false;
// 假如是其它节点
if (nodeEle.isElement())
{
QDomNode parentEle = nodeEle.parentNode();
if (parentEle.isElement())
parentEle.removeChild(nodeEle);
else
return false;
}
4.修改元素节点
这里也分2种情况:修改节点文本与修改节点属性。
与之前删除节点类似,找到节点后,不能直接修改该节点文本,需要利用新的文本替换该节点文本,具体操作如下:
if(nodeEle.isElement())
{
QDomNode oldnode = nodeEle.firstChild(); //标签之间的内容作为节点的子节点出现,得到原来的子节点
nodeEle.firstChild().setNodeValue(_nodeText); //用提供的value值来设置子节点的内容
QDomNode newnode = nodeEle.firstChild(); //值修改过后
nodeEle.replaceChild(newnode,oldnode); //调用节点的replaceChild方法实现修改功能
}
5.查询元素节点
这里也分2种情况:查询节点文本与查询节点属性。
与之前删除节点类似,找到节点后,分别利用QDomElement的text()与attribute()方法获取节点的文本与属性具体操作如下:
if(nodeEle.isElement()) {
QDomNode oldnode = nodeEle.firstChild(); //标签之间的内容作为节点的子节点出现,得到原来的子节点
nodeEle.firstChild().setNodeValue(_nodeText); //用提供的value值来设置子节点的内容
QDomNode newnode = nodeEle.firstChild(); //值修改过后
nodeEle.replaceChild(newnode,oldnode); //调用节点的replaceChild方法实现修改功能
}
另还有QXmlWrapper实现了查询所有子节点的文本等功能。想要获取完成的代码可以查看这里点击打开链接。