使用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文件为树形组织结构,以惟一根元素开始,层次式记录各属性、元素等信息,例如下文件为描述一目录树结构:
- xml version="1.0" encoding="ISO-8859-1"?>
- <FOLDER_ROOT>
- <FOLDER name="Folder1" attrib="rw">
- <FILE name="FileA" />
- FOLDER>
- <FOLDER name="Folder2" attrib="rw" />
- FOLDER_ROOT>
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;
- static xmlNodePtr pxmlroot = NULL;
-
- int prj_xml_writefile()
- {
-
- pxmldoc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
- if (NULL == pxmldoc)
- {
- return -1;
- }
-
- pxmlroot = xmlNewDocNode(pxmldoc, NULL, BAD_CAST PRJ_XML_ROOT, NULL);
- if (NULL == pxmlroot)
- {
-
- xmlFreeDoc(pxmldoc);
- pxmldoc = NULL;
- return -1;
- }
-
- (void)xmlDocSetRootElement(pxmldoc, pxmlroot);
-
- (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()
- {
- 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};
- xmlChar *npath;
- npath = xmlGetNodePath(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);
- 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);
- xmlXPathFreeContext(pctx);
- return 0;
- }
6. 环境清理
在完成XML文件操作后,需进行资源清理。清理前保证修改信息写入文件,可使用上文提到xmlSaveFileEnc()完成。清理环境操作如:
- int32 prj_xml_clear()
- {
- if (NULL != pxmldoc)
- {
-
- xmlFreeDoc(pxmldoc);
- pxmldoc = NULL;
- pxmlroot = NULL;
- }
-
- xmlCleanupParser();
- return 0;
- }
以上是在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
阅读(1640) | 评论(0) | 转发(0) |