您的位置:首页 > 运维架构 > Linux

Linux环境下使用Libxml2库

2008-07-28 16:48 375 查看
使用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"?>

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参考手册

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息