libxml的使用(1)--讀取xml


 

       libxml是一個用於解析xml文件的庫,在各個平台下都能使用,也支持多種語言,如c,Python等。這里是官方網站。上面有libxml的api和一些code examples,都是英文的。不過比較簡單。

libxml的基礎功能就是對xml的讀和寫。下面將簡單介紹libxml的讀的功能。(大部分內容是參照libxml tutorial 的文檔)

 

0 編譯程序

因為本人是在Linux下用C語言來介紹libxml的,所以使用了gcc編譯器。其他的編譯命令請參照官網。

我們知道,gcc 最簡單的編譯命令為gcc filename.c 。只要給這個命令添加頭文件和鏈接庫的地址就可以使用libxml。而libxml也提供了一個腳本xml2-config來配置這些地址。所以編譯時將命令改為gcc filename.c `xml2-config --cflags --libs`即可。cflags在編譯時提供頭文件的地址,而libs在鏈接時提供庫文件的地址。

1 分析文件--parse file

先簡單介紹xml文件。

 

<?xml version="1.0" encoding="UTF-8"?>
<root>
<node1>content1</node1>
<node2 attribute="yes">content2</node2>
<node3>
<subnode>go</subnode>
</node3>
</root>

上面是一個簡單的xml文件。從文件中很容易就能看出整個文件的結構和要表達的意思。下面我會結合xml的基本類型介紹這個文件。

文件的第一行是xml文件的一些屬性,可以看出編碼方式是utf-8 。libxml只能處理uft-8 和 utf-16編碼的文件,如果你的文件不是這兩種編碼,需要在使用前進行轉換。

<root></root>是xml的一個節點,即xmlNode。而xmlNodePtr 表示指向xmlNode的指針--xmlNode*。<node1></node1>,<node2></node2>,<node3></node3>是這個node的子node,即xmlNodePtr->children或xmlNodePtr->xmlChildrenNode。所以<subnode></subnode>就是<node3></node3>的子node。

 

接下來就是解析文件了。

 

[cpp]  view plain copy print ?
 
 
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <stdlib.h>  
  4. #include <libxml/tree.h>  
  5. #include <libxml/parser.h>  

 

文件中需要包含這兩個頭文件。

 

[cpp]  view plain copy print ?
 
 
  1. xmlDocPtr doc = NULL;  
  2. xmlNodePtr node = NULL;  
  3.   
  4. doc = xmlParseFile(filename);  
  5.   
  6. if(NULL  == doc) {  
  7.     fprintf(stderr, "parse error\n");  
  8.     exit(1);  
  9. }  

xmlDocPtr 表示指向xmlDoc的指針。從tutorial中我們可以知道,xmlDoc是一個包含了已解析的文件生成的節點樹的結構體。

 

 

[cpp]  view plain copy print ?
 
 
  1. node = xmlDocGetRootElement(doc);  
  2.   
  3. if(NULL == node) {  
  4.     fprintf(stderr, "doc has no content\n");  
[cpp]  view plain copy print ?
 
 
  1.     xmlFreeDoc(doc);  
  2.     exit(1);  
  3. }  

xmlDocGetRootElement(doc)可以得到整個文件的根節點,所有的操作都是從根節點開始的。

 

現在我們已經有了一個包含這個節點樹的結構體指針xmlDocPtr doc,有了一個可以操作節點的結構體指針xmlNodePtr node,我們就可以讀取各個節點的信息了。

節點包含這么幾個信息:

node->name:節點的名字,如node1,node2,subnode等

node->xmlChildrenNode:節點的子節點

node->last:節點的最后一個子節點

node->parent:節點的父節點

node->next:節點的兄弟節點,對於node1來說,node2和node3都是其兄弟節點,node1的next指向node2

由於節點的內容是其子節點(對於node1,content1可以說是其子節點),所以我們需要使用xmlNodeGetContent來取出內容。

 

[cpp]  view plain copy print ?
 
 
  1. node = node->xmlChildrenNode;  
  2. while(node != NULL) {  
  3.     printf("name=%s content=%s\n",  
  4.                node->name,  
  5.                (char*)xmlNodeGetContent(node));  
  6.     node=node->next;  
  7. }  

 

這是完整的源碼。

[cpp]  view plain copy print ?
 
 
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <stdlib.h>  
  4. #include <libxml/parser.h>  
  5.   
  6. static int  
  7. parseDoc(char* docname) {  
  8.     xmlDocPtr doc;  
  9.     xmlNodePtr cur;  
  10.     //xmlKeepBlanksDefault(0);  
  11.   
  12.     doc = xmlParseFile(docname);  
  13.   
  14.     if(doc == NULL) {  
  15.         fprintf(stderr, "doc error!\n");  
  16.         return 0;  
  17.     }  
  18.   
  19.     cur = xmlDocGetRootElement(doc);  
  20.   
  21.     if(cur == NULL) {  
  22.         fprintf(stderr, "root error!\n");  
  23.         xmlFreeDoc(doc);  
  24.         return 0;  
  25.     }  
  26.   
  27.     if(xmlStrcmp(cur->name, (const xmlChar*)"root")) {  
  28.         printf("end\n");  
  29.         return 0;  
  30.     }  
  31.   
  32.     cur = cur->children;  
  33.     while(cur != NULL) {  
  34.         printf("name=%s content=%s\n",cur->name,   
  35.                 (char*)xmlNodeGetContent(cur));  
  36.                 //cur->content);  
  37.         cur = cur->next;  
  38.     }  
  39.     xmlFreeDoc(doc);  
  40.     return 0;  
  41. }  
  42.   
  43. int main() {  
  44.     char* docname = "story.xml";  
  45.     parseDoc(docname);  
  46.     return 1;  
  47. }  


編譯鏈接后執行,會發現輸出的結果如下:

 

 

[cpp]  view plain copy print ?
 
 
  1. name=text content=  
  2.       
  3. name=node1 content=content1  
  4. name=text content=  
  5.       
  6. name=node2 content=content2  
  7. name=text content=  
  8.       
  9. name=node3 content=  
  10.         go  
  11.       
  12. name=text content=  

這是因為libxml默認將各個節點間的空格當作一個節點,只要在調用xmlParseFile之前調用xmlKeepBlanksDefault(0)即可。

 

修改后結果如下:

 

[cpp]  view plain copy print ?
 
 
  1. name=node1 content=content1  
  2. name=node2 content=content2  
  3. name=node3 content=go  

2 讀取內存中的xml文檔。

很多時候我們需要對內存中的xml文檔進行操作。比如在網絡編程的時候經常會從server那里接受一些客戶端的配置信息,這些配置信息大部分都是使用xml語言描述的。在你將這些信息讀入到buffer中后,你無需將他們寫入文件當中再分析,直接可以調用xmlReadMemory函數就可以得到一個xmlDocPtr。這個函數接受五個參數,第一個參數為緩存區的指針,第二個參數為緩存區大小,其他參數具體看API文檔。當然另外一個函數xmlReadDoc也能實現這樣的功能。

 

[cpp]  view plain copy print ?
 
 
  1. static char* config = "<config />";  
  2. xmlDocPtr doc = NULL;  
  3. xmlKeepBlanksDefault(0);  
  4.   
  5. doc = xmlReadMemory(config, strlen(config), "in_memory.xml", NULL, 0);  
  6.   
  7. //handle doc  
  8.   
  9. xmlFreeDoc(doc);  
 
0


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM