因一个应用里需要解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 这个路径节点 。