XPath在QT中的使用(QXmlQuery讀取XML檔案)
阿新 • • 發佈:2019-01-28
最近一段時間和Xml檔案算是幹上了,先後用了QXmlStream、Dom、Dhtmlxtree、DhtmlXform方式讀寫Xml檔案。昨天接到任務讓用Xpath方式實現Xml讀取。經過了解在QT中有QxmlQuery類用來實現XPath,接下來就說說這個東東!
1.lib檔案:
要想用QXmlQuery,首先要包含進兩個lib檔案:QtXmlPatterns4.lib 和 QtXmlPatternsd4.lib
2.標頭檔案:
用的一下這個標頭檔案
#include <QtXmlPatterns/QXmlQuery>
3.xml格式:
<?xml version="1.0"?> <tree id="0"> <item id="1" open="1" text="工作目錄" im0="leaf.gif" im1="folderOpen.gif" im2="folderClosed.gif" > <item id="11" select="1" text="工作目錄" im0="leaf.gif" im1="folderOpen.gif" im2="folderClosed.gif" > <userdata name="value"> <![CDATA[ <?xml version="1.0"?> <items> <item type="label" name="label1" label="基本配置"/> <item type="checkbox" name="check3" checked="true" label="全路徑" position="label-right" /> <item type="radio" name="ffff" checked="" value="online" label="單目錄" position="label-right" /> <item type="radio" name="ffff" checked="true" value="disk" label="雙目錄" position="label-right" /> <item type="checkbox" name="check1" checked="true" label="前目錄" position="label-right" /> <item type="checkbox" name="check2" checked="true" label="後目錄" position="label-right" /> <item type="select" name="myselect" label="傳遞方式" > <option text="post" value="op111" selected="" /> <option text="get" value="op222" selected="true" /> </item> <item type="input" name="inputx" value="2007.7.27更新" label="配置描述" rows="2" position="label-left" /> </items>]]> </userdata> </item> </item> <item id="2" open="1" text="資料伺服器地址" im0="leaf.gif" im1="folderOpen.gif" im2="folderClosed.gif" > <item id="21" text="地址" im0="leaf.gif" im1="folderOpen.gif" im2="folderClosed.gif" > <userdata name="value"> <![CDATA[<?xml version="1.0"?> <items> <item type="label" name="label1" label="基本配置"/> <item type="checkbox" name="check3" checked="true" label="全路徑" position="label-right" /> <item type="radio" name="ffff" checked="" value="online" label="單目錄" position="label-right" /> <item type="radio" name="ffff" checked="true" value="disk" label="雙目錄" position="label-right" /> </items>]]> </userdata> </item> </tree>
請仔細看我的xml格式,你會發現每一個二級目錄下會出現UserDate屬性,而內容竟然是個標準的xml檔案的語句,之所以這樣是專案的需要,這個格式有個好處,如果你對Dhtmlx庫瞭解的話,你會發現:外層的xml格式是DhtmlXTree的標準格式,而內層的xml格式為DhtmlxForm標準格式。明白了吧,實在不明白,上個圖吧:
看懂了吧,左側是個tree,右側自動生成form,而且還實現了,對form的寫入,具體程式碼在其他文章中提及了。好了,扯遠了。
4.關於QXmlQuery的使用
QXmlQuery query; QString sOptionSettings; QDomDocument configxmldoc; QFile db(sXmlPath); if ( ! db.exists()) { errMsg = "Xml檔案未找到!"; return errMsg; } if (!db.open(QIODevice::ReadOnly | QIODevice::Text)){ errMsg = "檔案打不開!"; return errMsg; } query.setFocus(&db); //去和我的xml格式對應一下,很容易就能看出來了。這句就是XPath的標準語法。 //sFistLabel,sSeconLabel都是引數,都=“工作目錄” query.setQuery("tree[@id='0']/item[@text='"+sFistLabel+"']/item[@text='"+sSeconLabel+"']/userdata[@name='value']"); //算是檢驗查詢引數有誤 if ( !query.isValid()){ errMsg = "查詢引數有誤!"; return errMsg; } //把查詢出來的語句,賦值給字串sOptionSettings query.evaluateTo(&sOptionSettings); db.close(); //以下三句與我的xml格式有關,要特別注意第一句,這裡預設給轉行了格式。其實正確的是(見下圖) sOptionSettings = sOptionSettings.replace("<","<").replace(">",">").replace("&","&"); sOptionSettings = sOptionSettings.replace("<userdata name=\"value\">",""); sOptionSettings = sOptionSettings.replace("</userdata>",""); //此時sOptionSettings是一個完整的xml語句, //而且configxmldoc為一個QDomDocument,接下來的事就是Dom解析xml格式 configxmldoc.setContent(sOptionSettings);
:
寫到這裡很多朋友可能會問,既然用Dom方式就能讀取Xml,幹嘛還用這種方式呢,其實仔細看看我的xml格式,你會發現用QXmlQuery讀我的外層xml格式會十分方便,這就是為什麼用這個了。
4.目標
最後說一下,我們這個任務
我的xml格式如上,當輸入(xml目錄、一級目錄、二級目錄、三級目錄、返回出錯資訊),會返回相應的value值。
整個程式碼如下:
QString PSM_OptionManager::get_config_info(const QString& sXmlPath, const QString& sFistLabel, const QString& sSeconLabel, const QString& sThridLabel, QString& errMsg){ QXmlQuery query; QString sOptionSettings; QDomDocument configxmldoc; QDomNodeList sitemNodes; QFile db(sXmlPath); if ( ! db.exists()) { errMsg = "Xml檔案未找到!"; return errMsg; } if (!db.open(QIODevice::ReadOnly | QIODevice::Text)){ errMsg = "檔案打不開!"; return errMsg; } query.setFocus(&db); query.setQuery("tree[@id='0']/item[@text='"+sFistLabel+"']/item[@text='"+sSeconLabel+"']/userdata[@name='value']"); if ( !query.isValid()){ errMsg = "查詢引數有誤!"; return errMsg; } query.evaluateTo(&sOptionSettings); db.close(); sOptionSettings = sOptionSettings.replace("<","<").replace(">",">").replace("&","&"); sOptionSettings = sOptionSettings.replace("<userdata name=\"value\">",""); sOptionSettings = sOptionSettings.replace("</userdata>",""); //此時sOptionSettings是一個完整的xml語句 configxmldoc.setContent(sOptionSettings); sitemNodes = configxmldoc.elementsByTagName("item"); for (int i = 0; i < sitemNodes.count(); i++) { QDomNode node = sitemNodes.at(i); QString itemlabel = node.toElement().attribute("label"); if (itemlabel == sThridLabel ){ QString itemtype = node.toElement().attribute("type"); if(itemtype == "checkbox" || itemtype == "radio") { QString itemchecked = node.toElement().attribute("checked"); if (itemchecked == "true"){ return "1"; } else{ return "0"; } }//end if if (itemtype == "input") { QString itemvalue = node.toElement().attribute("value"); return itemvalue; }//end if if (itemtype == "select"){ QDomNodeList optionlist = node.toElement().childNodes(); for (int j = 0 ; j < optionlist.count() ; j++) { QDomNode optionnode = optionlist.at(j); QString optionchecked = optionnode.toElement().attribute("selected"); if (optionchecked == "true"){ QString optionvalue = optionnode.toElement().attribute("value"); return optionvalue; } }//end for }//end if }//end if }//end for return ""; }
呼叫方式是:
QString sfist = "工作目錄";
QString ssecond = "工作目錄";
QString sthird = "全路徑";
QString sXmlPath = "E:\\settings.xml";
QString strErrMsg = "";
get_config_info(sXmlPath,sfist,ssecond,sthird, strErrMsg);
當然,我這是截取了一部分程式碼,因為我寫的QT外掛,所以呼叫程式碼實在另一個工程裡。
好了,就這些吧。
5.資料:
QT菜鳥一隻,歡迎批評指正!