因一个应用里需要解XML,tinyxml也许还可以,但是C++的,应用在C下,所以还是找一些C的,找了几个比较小的库解析使用都感觉不怎么样,最后还是使用libxml2吧,因同事应用里用也用了这个,木已成舟啊!!!,最后大家都用so文件。
libxml2编译
在其网站上下载libxml2,编译很简单,只要指定几个参数就可以了。如下:
第一步:
./configure --prefix=$HOME/libxml2_3531 --host=arm-hisiv100nptl-linux --with-debug=off
--host参数就是指定我使用的编译器,这里指定一个前缀就行了,应我用的是arm-hisiv100nptl-linux-gcc。
--prefix 指定了编译后保存的目录
第二步:
make
第三步:
make install
这样就好了,在指定的目录里就会有相应的动态和静态的库产生。
libxml2的使用
我用的功能其实很少,只是解析和查找,更改XML文档都没有用到,网上很多小的库,都是只有解析的功能,有的也有实现XPATH的,这样查找节点会很方便。
libxml解析XML
我的XML是从网络上接收到的SOAP包,XML都不会太大,我用的xmlParseMemory方法,当然也可以从文件里读XML。
如,我把收到的SOAP把XML放在一个BUFF里,再调用xmlParseMemory 解析,xmlParseMemory返回一个xmlDocPtr指针,这样我们就可认对一个XML文档做很多操作了,xmlXPathContext主要是用XPath来查找搜索XML节点的,有了这家伙,操作很灵活,所以找库最好找一个实现了XPATH的,可以上W3C学习一下XPATH的内容,很简单,用到XPATH的话,你可能还需要学习理解XML的命名空间,这个在W3C上也有资料。
如下的应用:
1
2
3
4
5
6
7
8
|
xmlDocPtr doc;
xmlXPathContextPtr context;
char
*MemoryBuff;
int
size;
doc = xmlParseMemory(MemoryBuff,size);
context = xmlXPathNewContext(doc);
for
(i=0;i<MAX-NS;i++)
//把命名空间注册,如果你解的XML里有命名空间的话,这一步就是需要的
xmlXPathRegisterNs(context,NS-NAME[i],NS[i])
|
libxml查找节点
查找节点可以使用如下的一个函数,来自LIBXML的文档里:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
xmlXPathContextPtr get_nodeset(xmlDocPtr doc, xmlChar *xpath){
xmlXPathObjectPtr result;
if
(context == NULL) {
printf
(
"Error in xmlXPathNewContext\n"
);
return
NULL;
}
result = xmlXPathEvalExpression(xpath, context);
if
(result == NULL) {
printf
(
"Error in xmlXPathEvalExpression\n"
);
return
NULL;
}
if
(xmlXPathNodeSetIsEmpty(result->nodesetval)){
xmlXPathFreeObject(result);
printf
(
"No result\n"
);
return
NULL;
}
//printf("result->nodesetval->nodeMax:%d\n",result->nodesetval->nodeMax);
return
result;
}
|
注意,上面返回的可能是多个节点,如果你只要查找其中的第一个节点,使问题简化,可以下面这样改一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
xmlNodePtr get_first_node(xmlDocPtr doc,xmlChar *xpath){
xmlNodePtr result;
xmlXPathObjectPtr path_ptr;
if
(context == NULL) {
printf
(
"Error in xmlXPathNewContext\n"
);
return
NULL;
}
path_ptr = xmlXPathEvalExpression(xpath, context);
if
(path_ptr == NULL) {
printf
(
"Error in xmlXPathEvalExpression\n"
);
return
NULL;
}
if
(xmlXPathNodeSetIsEmpty(path_ptr->nodesetval)){
xmlXPathFreeObject(path_ptr);
printf
(
"No result,path:%s\n"
,xpath);
return
NULL;
}
if
(path_ptr->nodesetval->nodeNr == 0)
return
NULL;
result = path_ptr->nodesetval->nodeTab[0];
//printf("result->nodesetval->nodeMax:%d\n",result->nodesetval->nodeMax);
return
result;
}
|
看上面的18行,你应去了解一下nodesetval这个结构,就很明白了,nodeNr记录的就是查找到的节点数.
如果知道了XPATH的知识,其实我们在查找节点时,可以利用XPATH的规则只返回第一个节点,或第二个节点...这样的指定。
假如我们解出了一个XML文档:
现在我们有了如下的指针
xmlDocPtr doc 。
//要查找一个节点,可以如下调用:
xmlNodePtr node_ptr = NULL;
if(docPtr){
node_ptr = get_first_node(doc ,"//SOAP-ENV:Body/SOAP-ENV:Fault/SOAP-ENV:Reason/SOAP-ENV:Text");
if(node_ptr){
print_debug_info("Back Failed,Reason text:%s",xmlNodeGetContent(node_ptr));
}
}
这样会查找 XML文档中是否有 SOAP-ENV:Body/SOAP-ENV:Fault/SOAP-ENV:Reason/SOAP-ENV:Text 这个路径节点 。