本文简单介绍libxml2的安装及基于C语言从xml文件中解析出相关内容。
参考博客:libxml2的安装及使用_阿卡基YUAN的博客-CSDN博客_libxml2
一、libxml2安装
1、源码安装:
gitee仓库:libxml2: libxml2压缩文件夹
解压
cd libxml2-2.7.4
./configure prefix=指定路径
make
make install
2、shell安装
sudo apt-get install libxml2
sudo apt-get install libxml2-dev
二、数据类型和函数
1、内部字符类型xmlChar
xmlChar是Libxml2中的字符类型,库中所有字符、字符串都是基于这个数据类型,类似char。很多libxml2的函数会返回一个动态分配内存的xmlChar*变量,所以使用这样的函数时要记得手动xmlFreeDoc(读入的文件)删除内存。
2、xmlChar相关函数
xmlMalloc是动态分配内存的函数;xmlFree是配套的释放内存函数;xmlStrcmp是字符串比较函数;xmlGetProp取出其属性值等。
3、文件类型xmlDoc、指针xmlDocPtr
xmlDoc是个struct,保存了一个xml的相关信息,例如文件名、文件类型、子节点等等;xmlDocPtr等于xmlDoc*。xmlReadFile函数读入一个带有某种编码的xml文件,并返回文件指针;细节见libxml2参考册。xmlFreeDoc释放文件指针。特别注意,当你调用xmlFreeDoc时,该文件所有包含的节点内存都被释放。
4、节点类型xmlNode、指针xmlNodePtr(与链表类似)
typedef struct _xmlNode xmlNode;
typedef xmlNode *xmlNodePtr;
struct _xmlNode {
void *_private;/* application data */
xmlElementType type; /* type number, must be second ! */
const xmlChar *name; /* the name of the node, or the entity */ 节点名字:name;
struct _xmlNode *children; /* parent->childs link */
struct _xmlNode *last; /* last child link */
struct _xmlNode *parent;/* child->parent link */
struct _xmlNode *next; /* next sibling link */
struct _xmlNode *prev; /* previous sibling link */
struct _xmlDoc *doc;/* the containing document */ 节点所属文件:doc;
/* End of common part */
xmlNs *ns; /* pointer to the associated namespace */
xmlChar *content; /* the content */ 节点中的文字内容:content;
struct _xmlAttr *properties;/* properties list */
xmlNs *nsDef; /* namespace definitions on this node */
void *psvi;/* for type/PSVI informations */
unsigned short line; /* line number */
unsigned short extra; /* extra data for XPath/XSLT */
};
三、解析xml实例
解析一个XML文档,从中取出想要的信息,例如节点中包含的文字,或者某个节点的属性。其流程如下:
1、用xmlReadFile函数读入一个文件,并返回一个文档指针doc。
2、用xmlDocGetRootElement函数得到根节点cur。
3、此时cur->xmlChildrenNode就是根节点的首个儿子节点,该儿子节点的兄弟节点可用next指针进行轮询。
4、轮询所有子节点,用xmlStrcmp与想找的内容作比较,等于0,即找到
5、取出该节点的属性,用xmlGetProp取出其属性值。
6、xmlFreeDoc函数关闭文档指针,并清除本文档中所有节点动态申请的内存。
xml例:apns-full-conf.xml(实际没有这么少内容,我删减了)
<apns version="8"> /* 这是根节点 */
<apn carrier="AT&T PHONE TEST SIM" /* 子节点 */
carrier_id = "1911" /* 节点的相关属性 */
mcc="001"
mnc="01"
apn="phone"
user=""
password=""
proxy=""
port=""
mmsc="http://mmsc.mobile.att.net"
mmsproxy="proxy.mobile.att.net"
mmsport="80"
type="default,mms,supl,hipri,fota,dun"
mtu="1410"
/>
<apn carrier="T-Mobile TEST SIM"
carrier_id = "1911"
mcc="001"
mnc="01"
apn="phone"
user=""
password=""
proxy=""
port=""
type="default,supl,hipri,dun"
mtu="1440"
/>
<apn carrier="CTNET"
carrier_id = "2237"
mcc="460"
mnc="03"
apn="ctnet"
user="ctnet@mycdma.cn"
password="vnet.mobi"
authtype="3"
server="*"
proxy=""
port="80"
mmsc=""
mmsproxy=""
mmsport=""
type="default,hipri,fota,cbs"
protocol="IP"
/>
<apn carrier="CTWAP"
carrier_id = "2237"
mcc="460"
mnc="03"
apn="ctwap"
user="ctwap@mycdma.cn"
password="vnet.mobi"
authtype="3"
server="*"
proxy=""
port="80"
mmsc="http://mmsc.vnet.mobi"
mmsproxy="10.0.0.200"
mmsport="80"
type="default,mms,hipri,supl,fota,cbs"
protocol="IP"
/>
</apns>
query_apn.c:(解析出APN)
#include <stdio.h>
#include <string.h>
#include <libxml2/libxml/xmlmemory.h>
#include <libxml2/libxml/parser.h>
#include <libxml/xmlversion.h>
#include <libxml/xmlstring.h>
#define FILE_NAME "/home/nbiot/pengjiawei/sms_-modem/apns-full-conf.xml"
void query_apn(char *file_name);
int main(int argc,char **argv)
{
query_apn(FILE_NAME);
return 0;
}
void query_apn(char *file_name)
{
xmlDocPtr doc; //文档指针
xmlNodePtr cur; //根节点
xmlChar *mcc; //移动国家代码
xmlChar *mnc; //移动网络代码
xmlChar *apn; //PPP拨号APN
/* 目标mcc与mnc */
char *qmcc = "460";
char *qmnc = "03";
if( !file_name )
{
printf("Invalid input arguments\n");
}
doc = xmlReadFile(file_name, "UTF-8", XML_PARSE_RECOVER); //读入需要解析的xml文件
if (doc == NULL)
{
printf("Failed to read xml file:%s\n", file_name);
goto cleanup;
}
cur = xmlDocGetRootElement(doc); //获取根节点
if (cur == NULL)
{
printf("Root is empty.\n");
goto cleanup;
}
if ( xmlStrcmp(cur->name, (const xmlChar *)"apns") ) //判断根节点是否正确,注意强制类型转换
{
printf("The root is not apns.\n");
goto cleanup;
}
cur = cur->xmlChildrenNode; //由根节点指向子节点
while (cur != NULL)
{
if ( xmlStrcmp(cur->name, (const xmlChar *)"apn")==0 ) //现在的cur->name子节点的name,判断name里有没有apn,若有,往下走
{
/* xmlGetProp取出其属性值 */
mcc = xmlGetProp(cur, "mcc");
mnc = xmlGetProp(cur, "mnc");
if( xmlStrcmp(mcc, (const xmlChar *)qmcc)==0 && xmlStrcmp(mnc, (const xmlChar *)qmnc)==0 ) //若mcc和mnc是460 03同时成立,则获取该子节点APN
{
apn = xmlGetProp(cur, "apn");
printf("mcc:%s mnc:%s apn:%s \n",mcc, mnc, apn);
break;
}
}
cur = cur->next; //若不满足条件则指向下一个子节点
}
cleanup:
if (doc)
{
xmlFreeDoc(doc);
}
}
编译:(安装的源码要记得指定头文件和库的位置)
gcc query_apn.c -o query_apn -I /home/nbiot/pengjiawei/libxml2/include/libxml2 -L /home/nbiot/pengjiawei/libxml2/lib -lxml2
结果: