1. 程式人生 > >XPath在QT中的使用(QXmlQuery讀取XML檔案)

XPath在QT中的使用(QXmlQuery讀取XML檔案)

  最近一段時間和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菜鳥一隻,歡迎批評指正!