天天看點

Linux環境下使用Libxml2庫

使用XML技術可以友善的完成資料檔案的存儲及解析讀取,其格式化、解析過程由XML引擎完成,在Windows平台上可使用MSXML引擎,在Linux環境下可使用libxml2庫完成操作。本文簡要整理了在Linux環境下使用libxml2進行XML操作的C語言程式設計方式,包括檔案建立、讀寫操作。

  Libxml2庫提供DOM、SAX操作接口,也實作了DTD、Scheme方式的驗證,支援XPath文法查詢,加上其穩定性及可移植性,滿足了一般項目的要求,有關Libxml2具體介紹可參考【1】。

1. 環境初始化

  使用Libxml2庫,應確定在編譯環境中(尤其對于客戶機編譯安裝的分發軟體)需要相關頭檔案及連結庫,則可以通過Libxml2預定義宏确認:

#include 
 
  
#include 
  
   
#include 
   
    
#include 
    
     
#include 
     
      
#include 
      
        #include 
       
         #if !(defined(LIBXML_WRITER_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) / && defined LIBXML_READER_ENABLED) #error "cannot use xml lib" #endif
       
      
     
    
   
  
       

使用Libxml2進行XML檔案解析,則初始化解析環境,使其配置設定相應資源、設定變量。在實驗中,省略該步驟并未影響操作結果,但在記憶體檢查中會出現警告,可能導緻未預期結果。

int prj_xml_init()
{
    xmlInitParser();
    LIBXML_TEST_VERSION
    return 0;
}      

2. 寫入XML檔案

  XML檔案為樹形組織結構,以惟一根元素開始,層次式記錄各屬性、元素等資訊,例如下檔案為描述一目錄樹結構:

Libxml2使用XML檔案指針操作XML檔案,使用XML節點指針操作節點,可使用xmlNewDoc()和xmlDocSetRootElement()建立,使用xmlSaveFileEnc儲存,例如:

#define PRJ_XML_ENCODING "ISO-8859-1"   /* 編碼方式   */
#define PRJ_XML_FILEPATH  "/home/prj/prjconf.xml" /* 檔案路徑   */
#define PRJ_XML_ROOT     "FOLDER_ROOT"  /* 根節點标簽 */
static xmlDocPtr  pxmldoc = NULL; /*** XML資料檔案文檔執行個體 ***/
static xmlNodePtr pxmlroot = NULL; /*** XML資料檔案根節點   ***/

int prj_xml_writefile()
{
  /*建立檔案 */
  pxmldoc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
  if (NULL == pxmldoc)
  {
      return -1;
  }
  /* 構造xml檔案句柄 */
  pxmlroot = xmlNewDocNode(pxmldoc, NULL, BAD_CAST PRJ_XML_ROOT, NULL);
  if (NULL == pxmlroot)
  {
    /* 失敗時清理資源 */
    xmlFreeDoc(pxmldoc);
    pxmldoc = NULL;
    return -1;
  }
  /* 構造xml根節點 */
  (void)xmlDocSetRootElement(pxmldoc, pxmlroot);
  /* 儲存新XML資料檔案 */
  (void)xmlSaveFileEnc(PRJ_XML_PATH, pxmldoc, PRJ_XML_ENCODING);
}      

3. 寫入節點資訊

  在XML檔案樹中建立子節點并寫入節點資訊,需要指明該節點的标簽及父節點,使用xmlNewChild()建立;增加、修改屬性資訊使用xmlNewProp()和xmlSetProp(),例如:

#define PRJ_XML_FOLDER " FOLDER"  /* Folder節點标簽 */
#define PRJ_XML_FILE        "FILE"          /* File節點标簽   */
int prj_xml_newfolder()  /* 增加Folder節點 */
{
  xmlNode *pnode = NULL;

  pnode = xmlNewChild(pxmlroot,NULL, BAD_CAST PRJ_XML_FOLDER, NULL);
  if (NULL == pnode)
  {
    return NULL;
  }
  /* 增加屬性 */
  (void)xmlNewProp(pnode, BAD_CAST "name", BAD_CAST "");
  (void)xmlNewProp(pnode, BAD_CAST "attrib", BAD_CAST "");
  return pnode;
}

int prj_xml_setprop(xmlNode *pnode, const char *attrib, const char *value) /* 修改屬性 */
{
  return xmlSetProp(pnode, BAD_CAST attrib, BAD_CAST value);
}
      

4. 讀取節點資訊

  Libxml2使用一個樹型結構組織XML檔案的全部資訊,包括節點的子節點、屬性等,則可以通過直接使用節點指針讀取資訊,但不是個通用方式。使用xmlReader和xmlWriter子產品可完成大量讀寫操作,可參考【2】。

對于基本的的讀取,可使用xmlGetProp()完成,它傳回一個xmlChar類型的字元數組包含屬性資訊,在使用完成後手動釋放資源,例如:

int prj_xml_readprop(xmlNode *pnode, const char *attrib) /* 讀取屬性 */
{
  xmlChar *strres = NULL;
  strres = xmlGetProp(pnode, BAD_CAST attrib);
  if (NULL == strres)
  {
    return -1;
  }
  /* 其他操作 */
  /* 清理資源 */
  xmlFree(strres);
  return 0;
}      

5. 使用XPath查詢節點集

  使用XPath文法可以表示特定的節點集,執行XPath語句則完成了查找特定節點集的功能。基本流程為:生成XPath查詢字元串、初始化XPath查詢環境、執行查詢獲得結果集、操作結果集、清理XPath查詢環境。

  XPath文法有豐富的路徑表達方式、運算符及運算函數,可以完成複雜的節點查詢。例如:

查詢某Folder節點pnode下的所有檔案名以”File”開頭的檔案節點。使用GetNodePath()得到pnode的路徑字元串,使用start-with函數查詢。

char expr[64]={0};    /* 存放XPath語句 */
  xmlChar *npath;
  npath = xmlGetNodePath(pnode); /* 得到pnode的路徑字元串 */
  (void)snprintf(expr, 64, "%s/%s[starts-with(@path,'%s/')]",
              (const char *)npath, PRJ_XML_FILE, "File");
  xmlFree(npath);      

又如查詢名為”Folder2”的檔案夾,但在Windows上名稱對大小寫不敏感,則可以使用lower-case()函數将節點屬性轉為小寫再比較。對于Libxml2,暫未支援這個在xml2.0定義的函數,是以需要translat()函數代替,自然有性能的消耗:

FOLDER_ROOT/FOLDER[translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')='Folder2']

  生成XPath語句後,則可進行查詢得到查詢結果集,集合可能含有0、1或多個元素,然後進行具體操作:

int prj_xml_xpath_evaluate(const xmlChar* expr, xmlNodePtr *ppnode)
{
  xmlXPathContextPtr pctx = NULL;
  xmlXPathObjectPtr  pobj = NULL;
  if (NULL == expr)
  {
      return -1;
  }
  pctx = xmlXPathNewContext(pxmldoc); /* 初始化XPath查詢環境 */
  if (NULL == pctx)
  {
      return -1;
  }
  pobj = xmlXPathEvalExpression(BAD_CAST expr,pctx); /* 執行查詢 */
  if (NULL == pobj)
  {
      xmlXPathFreeContext(pctx);
      return -1;
  }
  if (0 == pobj->nodesetval->nodeNr) /* 結果集為空 */
  {
    /* 其他操作 */
  }
  else
  {
    /* 其他操作 */
  }
  
  xmlXPathFreeObject(pobj);  /* 清理XPath查詢環境 */
  xmlXPathFreeContext(pctx);
  return 0;
}      

6.   環境清理

  在完成XML檔案操作後,需進行資源清理。清理前保證修改資訊寫入檔案,可使用上文提到xmlSaveFileEnc()完成。清理環境操作如:

int32 prj_xml_clear()
{
  if (NULL != pxmldoc)
  {
    /* 清理文檔連結清單資源 */
   xmlFreeDoc(pxmldoc);
   pxmldoc = NULL;
   pxmlroot = NULL;
  }
  /* 通知xml解析結束 */
  xmlCleanupParser();
  return 0;
}      

 以上是在Linux環境是使用Libxml2庫完成XML操作的基本方式,完成複雜、具體需求的操作也可以通過參考資源資訊進行實驗完成。

  Stone&Ice

  From: http://blog.csdn.net/stoneandice

參考資源:

1. http://xmlsoft.org/ Libxml2官方網站

2. http://www.w3school.com.cn/x.asp W3school的XML參考手冊

繼續閱讀