Linux C]利用libxml2解析xml文件

为了解析xml,可以使用Linux下默认安装的libxml2。

[cpp]  view plain copy
  1. /* 
  2.     a.c 
  3.     功能:利用libxml2解析xml文件 
  4. */  
  5.   
  6. #include <stdio.h>  
  7. #include <stdlib.h>  
  8. #include <string.h>  
  9. #include <unistd.h>  
  10. #include <libgen.h>  
  11. #include <libxml/xmlmemory.h>  
  12. #include <libxml/parser.h>  
  13. #include <libxml/xpath.h>  
  14.   
  15. int GetCurFilePath(char *lpOut)     // get full path of the executable file  
  16. {  
  17.     char chPath[BUFSIZ] = {0};  
  18.     int nRetVal = readlink("/proc/self/exe", chPath, sizeof(chPath)); // get full path of the current-executable file  
  19.     if(nRetVal < 0)  
  20.     {  
  21.         strcpy(lpOut, ".");  
  22.         return -1;  
  23.     }  
  24.     else  
  25.     {  
  26.         strcpy(lpOut, chPath);  
  27.         return 0;  
  28.     }  
  29. }  
  30.   
  31. int GetCurDir(char *lpOut)                                  // get directory-path of current executable-file  
  32. {  
  33.     char    chPath[BUFSIZ] = { 0 };  
  34.     if( GetCurFilePath(chPath) < 0 )  
  35.         return - 1;  
  36.     dirname(chPath);                                        // dirname will change value of "chPath"(contain result)  
  37.     strcpy(lpOut, chPath);                                  // copy result to out-param  
  38.   
  39.     return 0;  
  40. }  
  41.   
  42. xmlDocPtr getdoc(char *docname)                         // 根据文件名得到文档指针  
  43. {  
  44.     xmlDocPtr doc;  
  45.     doc = xmlParseFile(docname);  
  46.     if(doc == NULL)  
  47.     {  
  48.         fprintf(stderr, "Document not parsed successfully.\n");  
  49.         return NULL;  
  50.     }  
  51.     return doc;  
  52. }  
  53.   
  54. // 在文档doc中解析xpath表达式,返回结果集指针  
  55. xmlXPathObjectPtr getnodeset(xmlDocPtr doc, xmlChar *xpath)  
  56. {  
  57.     xmlXPathContextPtr context;  
  58.     xmlXPathObjectPtr result;  
  59.     context = xmlXPathNewContext(doc);  
  60.     if(context == NULL)  
  61.     {  
  62.         printf("Error in xmlXPathNewContent\n");  
  63.         return NULL;  
  64.     }  
  65.     result = xmlXPathEvalExpression(xpath, context);        // 在context中解析表达式xpath  
  66.     xmlXPathFreeContext(context);                           // 释放context  
  67.     if(result == NULL)  
  68.     {  
  69.         printf("Error in xmlXPathEvalExpression\n");  
  70.         return NULL;  
  71.     }  
  72.     if(xmlXPathNodeSetIsEmpty(result->nodesetval))           // 解析表达式的结果集为空  
  73.     {  
  74.         xmlXPathFreeObject(result);  
  75.         printf("No result\n");  
  76.         return NULL;  
  77.     }  
  78.     return result;  
  79. }  
  80.   
  81. // 解析xmlPath路径的结点  
  82. void testReadXmlDoc(char *filepath, char *xmlPath)  
  83. {  
  84.     xmlDocPtr doc = getdoc(filepath);  
  85.     if(NULL == doc)  
  86.         return ;  
  87.   
  88.     xmlChar *xpath = (xmlChar*) xmlPath;  
  89.     xmlXPathObjectPtr result = getnodeset(doc, xpath);          // 获取结果集  
  90.     if(result)  
  91.     {  
  92.         xmlNodeSetPtr nodeset = result->nodesetval;  
  93.         xmlChar *name, *value;  
  94.         printf("nodeset->nodeNr = %d\n", nodeset->nodeNr);        // 打印结果集中结点个数  
  95.         for(int i = 0; i < nodeset->nodeNr; i++)  
  96.         {  
  97.             xmlNodePtr cur = nodeset->nodeTab[i];                // products  
  98.             printf("cur->name = %s\n", cur->name);  
  99.             cur = cur->xmlChildrenNode;  
  100.             while(cur)  
  101.             {  
  102.                 if(xmlStrcmp(cur->name, (const xmlChar*) "text"))        // cur->name不为"text"  
  103.                 {  
  104.                     printf("cur->name = %s\t", cur->name);  
  105.                     name = xmlGetProp(cur, (const xmlChar*) "name");    // 获取属性值  
  106.                     value = xmlGetProp(cur, (const xmlChar*) "value");  
  107.                     printf("name = %s, value = %s\n", name, value);  
  108.                     xmlFree(name);  
  109.                     xmlFree(value);  
  110.                 }  
  111.                 cur = cur->next;  
  112.             }  
  113.             printf("\n");  
  114.         }  
  115.         xmlXPathFreeObject(result);  
  116.     }  
  117.     xmlFreeDoc(doc);  
  118.     xmlCleanupParser();  
  119. }  
  120.   
  121. int main(void)  
  122. {  
  123.     char curDir[100] = {0};  
  124.     char docname[100] = {0};  
  125.     GetCurDir(curDir);  
  126.     strcpy(docname, curDir);  
  127.     strcat(docname, "/dprod.xml");  
  128.     testReadXmlDoc(docname, "/allproducts/products");  
  129.   
  130.     return EXIT_SUCCESS;  
  131. }  

makefile文件:

[python]  view plain copy
  1. CC=gcc  
  2. CFLAGS=  
  3. BIN=a  
  4. INC=/usr/include/libxml2  
  5.   
  6. $(BIN): $(BIN).c  
  7.     $(CC) $(CFLAGS) -o $(BIN) $(BIN).c -I$(INC) -lxml2 -std=c99  
  8.   
  9. clean:  
  10.     rm -f *.o $(BIN)  

xml文件(dprod.xml)内容:

[html]  view plain copy
  1. <?xml version="1.0"?>  
  2. <allproducts>  
  3.   <products>  
  4.     <product name="name11" value="value11" />  
  5.     <product name="name12" value="value12" />  
  6.     <product name="name13" value="value13" />  
  7.     <product name="name14" value="value14" />  
  8.   </products>  
  9.   <products>  
  10.     <product name="name21" value="value21" />  
  11.     <product name="name22" value="value22" />  
  12.     <product name="name23" value="value23" />  
  13.   </products>  
  14.   <products>  
  15.     <product name="name31" value="value31" />  
  16.     <product name="name32" value="value32" />  
  17.   </products>  
  18. </allproducts>  

编译运行:

[plain]  view plain copy
  1. [zcm@tmp #115]$make  
  2. gcc  -o a a.c -I/usr/include/libxml2 -lxml2 -std=c99  
  3. a.c: 在函数‘GetCurFilePath’中:  
  4. a.c:18: 警告:隐式声明函数‘readlink’  
  5. [zcm@tmp #116]$./a  
  6. nodeset->nodeNr = 3  
  7. cur->name = products  
  8. cur->name = product  name = name11, value = value11  
  9. cur->name = product  name = name12, value = value12  
  10. cur->name = product  name = name13, value = value13  
  11. cur->name = product  name = name14, value = value14  
  12.   
  13. cur->name = products  
  14. cur->name = product  name = name21, value = value21  
  15. cur->name = product  name = name22, value = value22  
  16. cur->name = product  name = name23, value = value23  
  17.   
  18. cur->name = products  
  19. cur->name = product  name = name31, value = value31  
  20. cur->name = product  name = name32, value = value32  
  21.   
  22. [zcm@tmp #117]$  


说明:对于编译中出现的“a.c:18: 警告:隐式声明函数‘readlink’”错误,实在不能明白。我查了下手册,这个函数在unistd.h中,而且我也已经#include了,为什么还会出现这个错误呢?

后来突然想到,可能是-std=c99的原因,将它改为-std=gnu99后,这个警告就没有了!


--------------------------------------------------------------------------------------------------------------------------------------------------

修改了xml文件和上面源码中的testReadXmlDoc()后,发现结果相当神奇,看来对libxml2的理解还是比较缺乏。

1. 修改xml文件内容:

[html]  view plain copy
  1. <?xml version="1.0"?>  
  2. <allproducts>  
  3.   <products>h1  
  4.     <product name="name11" value="value11" />h2  
  5.     <product name="name12" value="value12" />h3  
  6.     <product name="name13" value="value13" />h4  
  7.     <product name="name14" value="value14" />h5  
  8.   </products>  
  9.   <products>  
  10.     <product name="name21" value="value21" />  
  11.     <product name="name22" value="value22" />  
  12.     <product name="name23" value="value23" />  
  13.   </products>  
  14.   <products>  
  15.     <product name="name31" value="value31" />g1  
  16.     <product name="name32" value="value32" />  
  17. g2</products>  
  18. </allproducts>  

2. 修改testReadXmlDoc()

[cpp]  view plain copy
  1. // 解析xmlPath路径的结点  
  2. void testReadXmlDoc(char *filepath, char *xmlPath)  
  3. {  
  4.     xmlDocPtr doc = getdoc(filepath);  
  5.     if(NULL == doc)  
  6.         return ;  
  7.   
  8.     xmlChar *xpath = (xmlChar*) xmlPath;  
  9.     xmlXPathObjectPtr result = getnodeset(doc, xpath);          // 获取结果集  
  10.     if(result)  
  11.     {  
  12.         xmlNodeSetPtr nodeset = result->nodesetval;  
  13.         xmlChar *name, *value;  
  14.         printf("nodeset->nodeNr = %d\n", nodeset->nodeNr);        // 打印结果集中结点个数  
  15.         for(int i = 0; i < nodeset->nodeNr; i++)  
  16.         {  
  17.             xmlNodePtr cur = nodeset->nodeTab[i];                // products  
  18.             printf("cur->name = %s\n", cur->name);  
  19.             cur = cur->xmlChildrenNode;  
  20.             int ctext = 0;  
  21.             while(cur)  
  22.             {  
  23.                 if(xmlStrcmp(cur->name, (const xmlChar*) "text"))        // cur->name不为"text"  
  24.                 {  
  25.                     printf("cur->name = %s\t", cur->name);  
  26.                     name = xmlGetProp(cur, (const xmlChar*) "name");    // 获取属性值  
  27.                     value = xmlGetProp(cur, (const xmlChar*) "value");  
  28.                     printf("name = %s, value = %s\n", name, value);  
  29.                     xmlFree(name);  
  30.                     xmlFree(value);  
  31.                 }  
  32.                 else  
  33.                 {  
  34.                     ctext++;  
  35.                     xmlChar *v = xmlNodeListGetString(doc, cur, 1);  
  36.                     printf("cur->content = [%s], v = [%s]", cur->content, v); // cur->content获取cur的内容  
  37.                     xmlFree(v);  
  38.                 }  
  39.                 cur = cur->next;  
  40.             }  
  41.             printf("ctext = %d\n", ctext);  
  42.             printf("\n");  
  43.         }  
  44.         xmlXPathFreeObject(result);  
  45.     }  
  46.     xmlFreeDoc(doc);  
  47.     xmlCleanupParser();  
  48. }  


运行结果:

[plain]  view plain copy
  1. [zcm@tmp #168]$make  
  2. gcc  -o a a.c -I/usr/include/libxml2 -lxml2 -std=gnu99  
  3. [zcm@tmp #169]$./a  
  4. nodeset->nodeNr = 3  
  5. cur->name = products  
  6. cur->content = [h1  
  7.     ], v = [h1  
  8.     h2  
  9.     h3  
  10.     h4  
  11.     h5  
  12.   ]cur->name = product   name = name11, value = value11  
  13. cur->content = [h2  
  14.     ], v = [h2  
  15.     h3  
  16.     h4  
  17.     h5  
  18.   ]cur->name = product   name = name12, value = value12  
  19. cur->content = [h3  
  20.     ], v = [h3  
  21.     h4  
  22.     h5  
  23.   ]cur->name = product   name = name13, value = value13  
  24. cur->content = [h4  
  25.     ], v = [h4  
  26.     h5  
  27.   ]cur->name = product   name = name14, value = value14  
  28. cur->content = [h5  
  29.   ], v = [h5  
  30.   ]ctext = 5  
  31.   
  32. cur->name = products  
  33. cur->content = [  
  34.     ], v = [  
  35.       
  36.       
  37.       
  38.   ]cur->name = product   name = name21, value = value21  
  39. cur->content = [  
  40.     ], v = [  
  41.       
  42.       
  43.   ]cur->name = product   name = name22, value = value22  
  44. cur->content = [  
  45.     ], v = [  
  46.       
  47.   ]cur->name = product   name = name23, value = value23  
  48. cur->content = [  
  49.   ], v = [  
  50.   ]ctext = 4  
  51.   
  52. cur->name = products  
  53. cur->content = [  
  54.     ], v = [  
  55.     g1  
  56.       
  57. g2]cur->name = product   name = name31, value = value31  
  58. cur->content = [g1  
  59.     ], v = [g1  
  60.       
  61. g2]cur->name = product   name = name32, value = value32  
  62. cur->content = [  
  63. g2], v = [  
  64. g2]ctext = 3  
  65.   
  66. [zcm@tmp #170]$  

由此可见,一般情况下,我们用的比较多的可能会是cur->content这个东西了!


补充:

在网上看到一个人的写法,可以在解析xml文件时,直接忽略掉结点之间的无效空白。对于本文,就是将:

doc = xmlParseFile(docname); --->修改为:doc = xmlParseFile(docname, "UTF-8", XML_PARSE_NOBLANKS);  // 第3个参数是关键

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值