Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1202471
  • 博文数量: 261
  • 博客积分: 4196
  • 博客等级: 上校
  • 技术积分: 3410
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-17 17:05
文章分类

全部博文(261)

文章存档

2018年(1)

2017年(22)

2016年(2)

2015年(8)

2014年(27)

2013年(40)

2012年(161)

分类: LINUX

2012-04-12 09:36:07

使用XML技术可以方便的完成数据文件的存储及解析读取,其格式化、解析过程由XML引擎完成,在Windows平台上可使用MSXML引擎,在 Linux环境下可使用libxml2库完成操作。本文简要整理了在Linux环境下使用libxml2进行XML操作的C语言编程方式,包括文件创建、 读写操作。
  Libxml2库提供DOM、SAX操作接口,也实现了DTD、Scheme方式的验证,支持XPath语法查询,加上其稳定性及可移植性,满足了一般项目的要求,有关Libxml2具体介绍可参考【1】。

1. 环境初始化
  使用Libxml2库,应确保在编译环境中(尤其对于客户机编译安装的分发软件)需要相关头文件及链接库,则可以通过Libxml2预定义宏确认:

  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8.  
  9. #if !(defined(LIBXML_WRITER_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) /  
  10.       && defined LIBXML_READER_ENABLED)  
  11. #error "cannot use xml lib"  
  12. #endif  

使用Libxml2进行XML文件解析,则初始化解析环境,使其分配相应资源、设定变量。在实验中,省略该步骤并未影响操作结果,但在内存检查中会出现警告,可能导致未预期结果。

  1. int prj_xml_init()  
  2. {  
  3.     xmlInitParser();  
  4.     LIBXML_TEST_VERSION  
  5.     return 0;  
  6. }  

2. 写入XML文件
  XML文件为树形组织结构,以惟一根元素开始,层次式记录各属性、元素等信息,例如下文件为描述一目录树结构:

  1. xml version="1.0" encoding="ISO-8859-1"?>  
  2. <FOLDER_ROOT>  
  3.  <FOLDER name="Folder1" attrib="rw">  
  4.   <FILE name="FileA" />  
  5.  FOLDER>  
  6.  <FOLDER name="Folder2" attrib="rw" />  
  7. FOLDER_ROOT>  

Libxml2使用XML文件指针操作XML文件,使用XML节点指针操作节点,可使用xmlNewDoc()和xmlDocSetRootElement()创建,使用xmlSaveFileEnc保存,例如:

  1. #define PRJ_XML_ENCODING "ISO-8859-1"   /* 编码方式   */  
  2. #define PRJ_XML_FILEPATH  "/home/prj/prjconf.xml" /* 文件路径   */  
  3. #define PRJ_XML_ROOT     "FOLDER_ROOT"  /* 根节点标签 */  
  4. static xmlDocPtr  pxmldoc = NULL; /*** XML数据文件文档实例 ***/  
  5. static xmlNodePtr pxmlroot = NULL; /*** XML数据文件根节点   ***/  
  6.   
  7. int prj_xml_writefile()  
  8. {  
  9.   /*新建文件 */  
  10.   pxmldoc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);  
  11.   if (NULL == pxmldoc)  
  12.   {  
  13.       return -1;  
  14.   }  
  15.   /* 构造xml文件句柄 */  
  16.   pxmlroot = xmlNewDocNode(pxmldoc, NULL, BAD_CAST PRJ_XML_ROOT, NULL);  
  17.   if (NULL == pxmlroot)  
  18.   {  
  19.     /* 失败时清理资源 */  
  20.     xmlFreeDoc(pxmldoc);  
  21.     pxmldoc = NULL;  
  22.     return -1;  
  23.   }  
  24.   /* 构造xml根节点 */  
  25.   (void)xmlDocSetRootElement(pxmldoc, pxmlroot);  
  26.   /* 保存新XML数据文件 */  
  27.   (void)xmlSaveFileEnc(PRJ_XML_PATH, pxmldoc, PRJ_XML_ENCODING);  
  28. }  

3. 写入节点信息
  在XML文件树中创建子节点并写入节点信息,需要指明该节点的标签及父节点,使用xmlNewChild()创建;增加、修改属性信息使用xmlNewProp()和xmlSetProp(),例如:

  1. #define PRJ_XML_FOLDER " FOLDER"  /* Folder节点标签 */  
  2. #define PRJ_XML_FILE        "FILE"          /* File节点标签   */  
  3. int prj_xml_newfolder()  /* 增加Folder节点 */  
  4. {  
  5.   xmlNode *pnode = NULL;  
  6.   
  7.   pnode = xmlNewChild(pxmlroot,NULL, BAD_CAST PRJ_XML_FOLDER, NULL);  
  8.   if (NULL == pnode)  
  9.   {  
  10.     return NULL;  
  11.   }  
  12.   /* 增加属性 */  
  13.   (void)xmlNewProp(pnode, BAD_CAST "name", BAD_CAST "");  
  14.   (void)xmlNewProp(pnode, BAD_CAST "attrib", BAD_CAST "");  
  15.   return pnode;  
  16. }  
  17.   
  18. int prj_xml_setprop(xmlNode *pnode, const char *attrib, const char *value) /* 修改属性 */  
  19. {  
  20.   return xmlSetProp(pnode, BAD_CAST attrib, BAD_CAST value);  
  21. }  

4. 读取节点信息
  Libxml2使用一个树型结构组织XML文件的全部信息,包括节点的子节点、属性等,则可以通过直接使用节点指针读取信息,但不是个通用方式。使用xmlReader和xmlWriter模块可完成大量读写操作,可参考【2】。
对于基本的的读取,可使用xmlGetProp()完成,它返回一个xmlChar类型的字符数组包含属性信息,在使用完成后手动释放资源,例如:

  1. int prj_xml_readprop(xmlNode *pnode, const char *attrib) /* 读取属性 */  
  2. {  
  3.   xmlChar *strres = NULL;  
  4.   strres = xmlGetProp(pnode, BAD_CAST attrib);  
  5.   if (NULL == strres)  
  6.   {  
  7.     return -1;  
  8.   }  
  9.   /* 其他操作 */  
  10.   /* 清理资源 */  
  11.   xmlFree(strres);  
  12.   return 0;  
  13. }  

5. 使用XPath查询节点集
  使用XPath语法可以表示特定的节点集,执行XPath语句则完成了查找特定节点集的功能。基本流程为:生成XPath查询字符串、初始化XPath查询环境、执行查询获得结果集、操作结果集、清理XPath查询环境。
  XPath语法有丰富的路径表达方式、运算符及运算函数,可以完成复杂的节点查询。例如:
查询某Folder节点pnode下的所有文件名以”File”开头的文件节点。使用GetNodePath()得到pnode的路径字符串,使用start-with函数查询。

  1. char expr[64]={0};    /* 存放XPath语句 */  
  2. xmlChar *npath;  
  3. npath = xmlGetNodePath(pnode); /* 得到pnode的路径字符串 */  
  4. (void)snprintf(expr, 64, "%s/%s[starts-with(@path,'%s/')]",  
  5.             (const char *)npath, PRJ_XML_FILE, "File");  
  6. xmlFree(npath);  

又如查询名为”Folder2”的文件夹,但在Windows上名称对大小写不敏感,则可以使用lower-case()函数将节点属性转为小写再 比较。对于Libxml2,暂未支持这个在xml2.0定义的函数,因此需要translat()函数代替,自然有性能的消耗:
FOLDER_ROOT/FOLDER[translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')='Folder2']
  生成XPath语句后,则可进行查询得到查询结果集,集合可能含有0、1或多个元素,然后进行具体操作:

  1. int prj_xml_xpath_evaluate(const xmlChar* expr, xmlNodePtr *ppnode)  
  2. {  
  3.   xmlXPathContextPtr pctx = NULL;  
  4.   xmlXPathObjectPtr  pobj = NULL;  
  5.   if (NULL == expr)  
  6.   {  
  7.       return -1;  
  8.   }  
  9.   pctx = xmlXPathNewContext(pxmldoc); /* 初始化XPath查询环境 */  
  10.   if (NULL == pctx)  
  11.   {  
  12.       return -1;  
  13.   }  
  14.   pobj = xmlXPathEvalExpression(BAD_CAST expr,pctx); /* 执行查询 */  
  15.   if (NULL == pobj)  
  16.   {  
  17.       xmlXPathFreeContext(pctx);  
  18.       return -1;  
  19.   }  
  20.   if (0 == pobj->nodesetval->nodeNr) /* 结果集为空 */  
  21.   {  
  22.     /* 其他操作 */  
  23.   }  
  24.   else  
  25.   {  
  26.     /* 其他操作 */  
  27.   }  
  28.     
  29.   xmlXPathFreeObject(pobj);  /* 清理XPath查询环境 */  
  30.   xmlXPathFreeContext(pctx);  
  31.   return 0;  
  32. }  

6.   环境清理
  在完成XML文件操作后,需进行资源清理。清理前保证修改信息写入文件,可使用上文提到xmlSaveFileEnc()完成。清理环境操作如:

  1. int32 prj_xml_clear()  
  2. {  
  3.   if (NULL != pxmldoc)  
  4.   {  
  5.     /* 清理文档链表资源 */  
  6.    xmlFreeDoc(pxmldoc);  
  7.    pxmldoc = NULL;  
  8.    pxmlroot = NULL;  
  9.   }  
  10.   /* 通知xml解析结束 */  
  11.   xmlCleanupParser();  
  12.   return 0;  
  13. }  
 以上是在Linux环境是使用Libxml2库完成XML操作的基本方式,完成复杂、具体需求的操作也可以通过参考资源信息进行实验完成。
  Stone&Ice
  From: http://blog.csdn.net/stoneandice
参考资源:
1.  Libxml2官方网站
2.  W3school的XML参考手册
原文:http://blog.csdn.net/stoneandice/article/details/2725725

 libxml2应用实例.doc  
阅读(1568) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~