Qt XML檔案的建立、讀取介紹以及“重寫XML不能覆蓋原內容問題”解決
簡介XML
XML(Extensible Markup Language,可擴充套件標記語言),是一種類似於HTML的標記語言,設計目的是用來傳輸資料,而不是顯示資料。XML的標籤沒有被預定義,使用者需要在使用時自行進行定義。XML是W3C(全球資訊網聯盟)的推薦標準。相對於資料庫表格的二維表示,XML使用的樹形結構更能表現出資料的包含關係,作為一種文字檔案格式,XML簡單明瞭的特性使得它在資訊儲存和描述領域非常流行。
Qt中提供了Qt XML模組來進行XML文件的處理,這裡主要提供了兩種解析方法: DOM方法,可以進行讀寫;SAX方法,可以進行讀取。但是,從Qt 5開始Qt XML模組不再提供維護,而是推薦使用Qt Core模組中的QXmlStreamReader和QXmlStreamWriter進行XML讀取和寫入,這是一種基於流的方法。
如果要使用Qt XML模組,需要在專案檔案(.pro檔案)中新增QT += xml一行程式碼。
標準的XML文件示例:
<?xml version="1.0" encoding="UTF-8"?> <library> <book id="01"> <title>Qt</title> <author>shiming</author> </book> <book id="02"> <title>Linux</title> <author>yafei</author> </book> </library>
DOM
DOM(Document Object Model,文件物件模型),是W3C的推薦標準。它提供了一個介面來訪問和改變一個XML檔案的內容和結構,可以將XML文件表示為一個儲存在記憶體中具有層次的樹檢視。文件本身由QDomDocument物件來表示,而文件樹中所有的DOM節點都是QDomNode類的子類。
在Qt中使用QDomProcessingInstruction類來表示XML說明。元素對應QDomElement類。屬性對應QDomAttr類。文字內容由QDomText類表示。所有的DOM節點,比如這裡的說明、元素、屬性和文字等,都使用QDomNode來表示。
下面用一個簡單的例項來介紹XML檔案的建立與讀取。
XML建立
//生成配置檔案
void Login::createConfigXML()
{
//配置檔案 引數
QDomDocument doc;
//根元素
QDomElement root;
//介面元素
QDomElement interface;
//介面子元素
QDomElement child;
//控制元件文字
QDomText text;
// 新增處理指令即XML說明
QDomProcessingInstruction instruction;
instruction = doc.createProcessingInstruction("xml",
"version=\"1.0\" encoding=\"UTF-8\"");
doc.appendChild(instruction);
// 新增根元素
root = doc.createElement("色選機軟體系統");
doc.appendChild(root);
//【一】管理員介面
interface = doc.createElement("管理員介面");
//...【1】
child = doc.createElement("工作模式");
text = doc.createTextNode("異色模式");
child.appendChild(text);
interface.appendChild(child);
root.appendChild(interface);
//【二】背景板介面
interface = doc.createElement("背景板介面");
//...【1】
child = doc.createElement("鏡頭號");
text = doc.createTextNode("1");
child.appendChild(text);
interface.appendChild(child);
//...【2】
child = doc.createElement("背景");
text = doc.createTextNode("紅色");
child.appendChild(text);
interface.appendChild(child);
//新增介面資料
root.appendChild(interface);
//建立配置檔案
QFile file("ColorConfig.xml");
if(!file.open(QIODevice::Truncate | QIODevice::WriteOnly))
{
QMessageBox::about(NULL, tr("錯誤"), tr("生成配置檔案失敗,請重試!"));
return;
}
QTextStream out(&file);
// 將文件儲存到檔案,4為子元素縮排字元數
doc.save(out, 4);
file.close();
}
生成的配置檔案內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<色選機軟體系統>
<管理員介面>
<工作模式>異色模式</工作模式>
</管理員介面>
<背景板介面>
<鏡頭號>1</鏡頭號>
<背景>紅色</背景>
</背景板介面>
</色選機軟體系統>
XML讀取
//讀取配置檔案
void Login::readConfigXML()
{
QFile file("ColorConfig.xml");
if(!file.exists())
{
QMessageBox::about(NULL, tr("提示"), tr("未發現配置檔案"));
return;
}
if (!file.open(QIODevice::ReadOnly))
return;
QDomDocument Qdoc;
if (!Qdoc.setContent(&file))
{
file.close();
return ;
}
file.close();
//【一】管理員介面
QDomNodeList list = Qdoc.elementsByTagName("管理員介面");
QDomNodeList child = list.at(0).childNodes();
for(int i = 0; i < child.count(); ++i)
{
//輸出子元素名
qDebug()<< child.at(i).toElement().tagName() << endl;
//輸出字元素資料
qDebug()<< child.at(i).toElement().text()) << endl;
}
//【二】背景板介面
list = Qdoc.elementsByTagName("背景板介面");
child = list.at(0).childNodes();
for(int i = 0; i < child.count(); ++i)
{
//輸出子元素名
qDebug()<< child.at(i).toElement().tagName() << endl;
//輸出字元素資料
qDebug()<< child.at(i).toElement().text()) << endl;
}
}
還有另一種方式讀取:
QFile file("ColorConfig.xml");
if (!file.open(QIODevice::ReadOnly)) return ;
QDomDocument doc;
if (!doc.setContent(&file)) { file.close(); return ; }
file.close();
QDomElement docElem = doc.documentElement();
QDomNode n = docElem.firstChild();
while(!n.isNull()) {
if (n.isElement()) {
QDomElement e = n.toElement();
QDomNodeList list = e.childNodes();
for (int i=0; i<list.count(); i++) {
QDomNode node = list.at(i);
if(node.isElement())
{
//輸出子元素名
qDebug()<< node.toElement().tagName() << endl;
//輸出字元素資料
qDebug()<< node.toElement().text()) << endl;
}
} n = n.nextSibling();
}
“重寫XML不能覆蓋原內容問題”解決
如果我們想覆蓋XML中的原資料,重新寫入資料,使用
file.open(QIODevice::Truncate | QIODevice::WriteOnly)
這種方式開啟檔案即可,Truncate 表示重寫,將原檔案資料清空。但是我在做專案中碰到如下問題,重新寫入資料時,原資料沒能覆蓋,新資料也添加了進去,如下:
<?xml version="1.0" encoding="UTF-8"?>
<色選機軟體系統>
<管理員介面>
<工作模式>異色模式</工作模式>
</管理員介面>
<背景板介面>
<鏡頭號>1</鏡頭號>
<背景>紅色</背景>
</背景板介面>
</色選機軟體系統>
<?xml version="1.0" encoding="UTF-8"?>
<色選機軟體系統>
<管理員介面>
<工作模式>黃白模式</工作模式>
</管理員介面>
<背景板介面>
<鏡頭號>3</鏡頭號>
<背景>藍色</背景>
</背景板介面>
</色選機軟體系統>
最終發現原因:
我的專案中,軟體開啟時,預設載入配置檔案的資料,然而我把讀取、建立XML元素的物件們設定為全域性的了,
//配置檔案 引數
QDomDocument doc;
//根元素
QDomElement root;
//介面元素
QDomElement interface;
//介面子元素
QDomElement child;
//控制元件文字
QDomText text;
導致軟體開啟時,讀取配置檔案,這些變數都被佔用,並沒有釋放。然後我再去重寫XML內容時,就不可以將已佔用的資料清空替換,導致新的配置檔案資料在原資料下方產生。
解決方法:
將這些讀取、建立XML元素的物件們設定為區域性變數,一次用完自動釋放,不妨礙其他操作。這樣就正確了。