在做4G拨号的时候,遇到从.xml文件获取数据的部分。所以趁机简单在菜鸟教程学习了xml。在使用libxml2库的时候,我们有必要先了解一下xml的语法规则。在了解xml的时候顺带又把HTML过了一下。
提示:以下是本篇文章正文内容,下面案例可供参考
1、XML 不是 HTML 的替代。
2、XML 和 HTML 为不同的目的而设计:
3、HTML 旨在显示信息,而 XML 旨在传输信息。
4、XML 是对 HTML 的补充。
在不谈语法规则的情况下,我们可以把XML看成是一棵树。是一颗每个节点都可以有属性的树,我们再通过API函数接口对其读取数据是也是通过类似对数的遍历来对其进行增删改查的。我是通过使用libxml2库来对.xml文件进行解析的,下面来给大家简单的介绍一下libxml2库的使用。
(具体的介绍就参考 http://xmlsoft.org/ 推荐英文好的去看)
Libxml2 是一个xml c语言版的解析器,本来是为Gnome项目开发的工具,是一个基于MIT License的免费开源软件。它除了支持c语言版以外,还支持c++、PHP、Pascal、Ruby、Tcl等语言的绑定,能在Windows、Linux、Solaris、MacOsX等平台上运行。功能还是相当强大的,相信满足一般用户需求没有任何问题。
Libxml2主要的优点有:
不足之处也是有的:
1、 下载libxml2
可从http://xmlsoft.org/官网下载,或者githome上自行下载。
2、 具体安装步骤
原码安装:
解压:$tar zxvf libxml2-2.6.20.tar.gz
进入解压后的安装目录:$cd libxml2-2.6.20
安装三部曲:
$./configure
$make
$make install
(在这里不推荐使用shell命令直接安装)
shell命令安装:
$ sudo apt-get install libxml2
$ sudo apt-get install libxml2-dev
他的函数主要都在一下三个头文件:
#include <libxml/parse.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
1.1 xml操作的基础结构及其指针类型
xmlDoc xmlDocPtr 文档对象的结构体及其指针
xmlNode xmlNodePtr 节点对象的结构体及其指针
xmlAttr xmlAttrPtr 节点属性的结构体及其指针
xmlNs xmlNsPtr 节点命名空间的结构及其指针
在上述的所以节点当中我们必须把xmlNode节点类型给搞明白了,这个节点可以说是这个库中最重要的一个节点。具体结构如下说明:
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 */
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 */
/* End of common part */
xmlNs *ns; /* pointer to the associated namespace */
xmlChar *content; /* the 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属性也是编程中经常用到的结构,其定义如下:
struct _xmlAttr {
void * _private; /* application data */
xmlElementType type; /* XML_ATTRIBUTE_NODE, must be second ! */
const xmlChar * name ; /*the name of the property */
struct _xmlNode * children; /*the value of the property */
struct _xmlNode * last; /*NULL */
struct _xmlNode * parent; /*child->parent link */
struct _xmlAttr * next; /*next sibling link */
struct _xmlAttr * prev; /*previous sibling link */
struct _xmlDoc * doc; /*the containing document */
xmlNs * ns; /*pointer to the associated namespace */
xmlAttributeType atype; /*the attribute type if validating */
void * psvi; /*for type/PSVI informations */
};
1.2 内部字符类型xmlChar
xmlChar是Libxml2中的字符类型,库中所有字符、字符串都是基于这个数据类型。事实上他的定义是:xmlstring.h
如同标准c中的char类型相同,xmlChar也有动态内存分配、字符串操作等相关函数。例如xmlMalloc是动态分配内存的函数;xmlFree是配套的释放内存函数;xmlStrcmp是字符串比较函数等等。
另外要注意,因为总是要在xmlChar和char之间进行类型转换,所以定义了一个宏BAD_CAST,其定义如下:xmlstring.h
#define BAD_CAST (xmlChar *)
1、清除空白符影响函数
函数功能 | 在分析XML数据是,去除空白字符。如果不去除空白字符,则这些字符也会被当做一个node来处理 |
---|---|
函数接口 | int xmlKeepBlanksDefault(int val) |
参数说明 | val:0或者1。0表示去除空白字符,1表示不去除返回值:0表示设置失败,1表示设置成功,一般不用判断 |
特别说明 | 在每一次迭代时最好都是使用,在我亲测的过程中发现每遇到一个空白行他就得调用一次,否则取出来的节点名是text(libxml2的所有库函数都会把空白符当作一个node) |
2、打开XML文档
函数功能 | 读出XML文档指针doc |
---|---|
函数接口 | xmlDocPtr xmlReadFile (const char * filename, const char * encoding, int options) |
参数说明 | filename: 目标文件的路径名或URL; encoding: 目标文件的编码方式,可以为NULL ; options: 枚举变量xmlParserOption中的一个值或多个值的组合,可以为0; 返回值: XML文档的树结构。解析失败返回NULL |
特别说明 | ; |
3、 XML文件载入和保存函数
函数功能 | 将XML文件从硬盘上载入到内存中,并且生成DOM树。使用完毕之后,需要用xmlFreeDoc()来释放资源 |
---|---|
函数接口 | xmlDocPtr xmlParseFile(const char * filename) |
参数说明 | filename:XML文件名称。返回值:如果载入成功,则返回这个文档的根节点。否则返回NULL |
特别说明 | 该函数没有亲测过,但知道其是怎么使用的。就类似与word里的保存,在添加完所有的节点,节点属性后再关闭该文当前调用其进行保存 |
4、创建和释放XML文档函数
函数功能 | 在内存中创建一个新的XML文档。所创建的文档需要使用xmlFreeDoc()来释放资源 |
---|---|
函数接口 | xmlDocPtr xmlNewDoc (const xmlChar * version) |
参数说明 | version:XML标准的版本,目前只能指定为“1.0” |
特别说明 | 使用时记得强制转换一下类型; |
函数功能 | 释放内存中的XML文档 |
---|---|
函数接口 | void xmlFreeDoc(xmlDocPtr cur) |
参数说明 | cur:需要释放的XML文档 |
特别说明 | 在打开文档后也要释放文档; |
5、XML节点操作函数
函数功能 | 获得根节点 |
---|---|
函数接口 | xmlNodePtr xmlDocGetRootElement(xmlDocPtr doc) |
参数说明 | doc:XML文档句柄。返回值:XML文档的根节点,或者NULL。 |
特别说明 | ; |
函数功能 | 设置根节点 |
---|---|
函数接口 | xmlNodePtr xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) |
参数说明 | doc:XML文档句柄root:XML文档的新的根节点返回值:如果该文档原来有根节点,则返回根节点,否则返回NULL |
特别说明 | ; |
函数功能 | 查找节点 |
---|---|
函数接口 | void xmlStrcmp(xmlNodePtr *cur, xmlChar * Nodename) |
参数说明 | cur:节点的指针;Nodename:所要查找的节点名字;返回值:0;如果没有该节点,则返回-1。 |
特别说明 | ; |
函数功能 | 获得节点的内容 |
---|---|
函数接口 | xmlChar * xmlNodeGetContent (xmlNodePtr cur) |
参数说明 | cur:节点的指针;返回值:节点的文本内容。如果该节点没有文本内容,则返回NULL。当返回值不为NULL时,需要用xmlFree()函数来释放返回的资源 |
特别说明 | ; |
函数功能 | 设置节点的内容长度 |
---|---|
函数接口 | void xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar * content, int len) |
参数说明 | cur:节点的指针 ; content:节点的新文本内容; len:节点新文本内容的长度 |
特别说明 | ; |
函数功能 | 判断该节点是否具有属性 |
---|---|
函数接口 | xmlNodePtr xmlHasProp( xmlNodePtr cur, xmlChar *propNode) |
参数说明 | cur:节点的指针 ; propNode:属性名 ; 返回值:成功为节点指针 |
特别说明 | ; |
函数功能 | 获得节点的属性 |
---|---|
函数接口 | xmlChar * xmlGetProp(xmlNodePtr node, const xmlChar * name) |
参数说明 | node:XML节点的指针; name:该节点的属性的名称; 返回值:该属性的值或者为NULL。如果不为NULL,则需要用xmlFree()来释放资源 |
特别说明 | ; |
函数功能 | 设置节点的属性(如果该属性已经存在,则替换其值) |
---|---|
函数接口 | xmlAttrPtr xmlSetProp(xmlNodePtr node, const xmlChar * name, const xmlChar * value) |
参数说明 | node:需要设置属性的节点; name:该节点的属性的名称;value:属性的值; 返回值:该属性的值 |
特别说明 | ; |
libxml2库还有大量的API接口,这里就不列举了(本人也没有全部搞明白,需要的可以到使用手册里查找,或者官网查询)。
在小编学习使用libxml2库的时候,也绕了很多坑。现在吧我所用到的都写到博客里记录下来在以后使用到时候能立即那里使用,在查找根节点的root->xmlChildrenNode->xmlChildrenNode 的属性的时候真的是被这个指针搞得头晕,出现了死循环。在调试的时候必须画图理解一下。还有就是text节点,每一个空白行都被当作一个node,每一次迭代前最好都加 xmlKeepBlanksDefault(0); 忽略空白符。
参考资料:
https://blog.csdn.net/fanwenjieok/article/details/52847105
https://www.runoob.com/xml/xml-usage.html