1、Libxml2是个C语言的XML程式库,能简单方便的提供对XML文件的各种操作,并且支持XPATH查询,及部分的支持XSLT转换等功能。
最简单的安装方法#sudo apt-get install libxml2 #sudo apt-get install libxml2-dev
2、xml主要的数据类型
(1)内部字符类型xmlCharxmlChar是Libxml2中的字符类型,库中所有字符、字符串都是基于这个数据类型。事实上它的定义是:xmlstring.h
typedef unsigned char xmlChar;
使用unsigned char作为内部字符格式是考虑到它能很好适应UTF-8编码,而UTF-8编码正是libxml2的内部编码,其它格式的编码要转换为这个编码才能在libxml2中使用。还经常可以看到使用xmlChar*作为字符串类型,很多函数会返回一个动态分配内存的xmlChar*变量,使用这样的函数时记得要手动删除内存。
(2)xmlChar相关函数
如同标准C中的char类型一样,xmlChar也有动态内存分配、字符串操作等相关函数。例如xmlMalloc是动态分配内存的函数,xmlFree是配套的释放内存函数,xmlStrcmp是字符串比较函数等。基本上xmlChar字符串相关函数都在xmlstring.h中定义,而动态内存分配函数在xmlmemory.h头文件中定义。(3)xmlChar*与其他类型之间的转换
在实际编程中,总是需要在xmlChar *和char *之间进行强制类型转换,所以定义了一个宏BAD_CAST,其定义如下:
#define BAD_CAST (xmlChar *)(4)XML中常用到的重定义
在XML程序中,会经常看到xmlChildrenNode这个名称,其实这个名称是定义在tree.h中的重定义。其重定义如下:
#define xmlChildrenNode children
(5)文档类型xmlDoc、指针xmlDocPtr
xmlDoc是一个struct,保存了一个xml的相关信息,例如文件名、文档类型、子节点等,xmlDocPtr等于xmlDoc * 。与文档指针相关函数有如下几个。xmlNewDoc函数创建一个新的文档指针。
xmlParseFile函数以默认方式读入一个UTF-8格式的文档,并返回文档指针。xmlReadFile函数读入一个带有某种编码的xml文档,并返回文档指针。
xmlFreeDoc释放文档指针。特别注意,当调用xmlFreeDoc时,该文档所有包含的节点内存都会被释放,所以一般来说不需要手工调用xmlFreeNode或者
xmlFreeNodeList来释放动态分配的节点内存,除非把该节点从文档中移除了。一般来说,一个文档中所有节点都应该动态分配,然后加入文档,最后调用
xmlFreeDoc一次释放所有节点申请的动态内存,这也是为什么我们在程序中很少看见xmlNodeFree的原因。
xmlSaveFile将文档以默认方式存入一个文件。
xmlSaveFormatFileEnc可将文档以某种编码格式存入一个文件中。(6)节点类型xmlNode、指针xmlNodePtr
节点是XML中最重要的元素,xmlNode代表XML文档中的一个节点,实现为一个struct,此结构内容很丰富也很重要,其定义在tree.h中,具体说明如下: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 */ 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 */ };
可以看到,节点之间是以链表和树两种方式同时组织起来的,next和prev指针可以组成链表,而parent和children可以组织为树。同时此结构还有以下重要成员:
doc:节点所属文档。
name:节点名字。
ns:节点的名字空间。
properties:节点属性列表。
XML文档的操作其根本原理就是在节点之间移动、查询节点的各项信息,并进行增加、删除、修改等操作。xmlDocSetRootElement函数可以将一个节点设置为某个文档的根节点,这是将文档与节点连接起来的重要手段,当有了根结点以后,所有子节点就可以依次连接上根节点,从而组织成为一个XML树。
(7)XML属性
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 */ }
(8)节点集合类型xmlNodeSet、指针类型xmlNodeSetPtr
节点集合代表一个由节点组成的变量,节点集合只作为XPath的查询结果而出现,因此被定义在xpath.h中,其定义如下:
typedef struct _xmlNodeSet xmlNodeSet; typedef xmlNodeSet *xmlNodeSetPtr; struct _xmlNodeSet { int nodeNr; /* number of nodes in the set */ int nodeMax; /* size of the array as allocated */ xmlNodePtr *nodeTab; /* array of nodes in no particular order */ };
可以看出,节点集合有三个成员,分别是节点集合的节点数、最大可容纳的节点数,以及节点数组头指针。对节点集合中各个节点的访问方法如下:
xmlNodeSetPtr nodeset = XPath查询结果;
for (int i = 0; i < nodeset->nodeNr; i++) { nodeset->nodeTab[i]; }
/* * ===================================================================================== * * Filename: 2.c * * Description: 创建xml文件 * * Version: 1.0 * Created: 2014年05月29日 19时04分37秒 * Revision: none * Compiler: gcc * * Author: leiyu,leiyujike1107@gmail.com * Company: Class 1107 of Computer Science and Technology * * ===================================================================================== */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <libxml/xmlmemory.h> #include <libxml/parser.h> int main() { xmlDocPtr doc = xmlNewDoc(BAD_CAST"1.0"); xmlNodePtr root_node = xmlNewNode(NULL,BAD_CAST"root"); xmlDocSetRootElement(doc,root_node); xmlNewTextChild(root_node,NULL,BAD_CAST "newNode1",BAD_CAST "newNode1 content"); xmlNewTextChild(root_node,BAD_CAST "newNode2",BAD_CAST "newNode2 content"); xmlNewTextChild(root_node,BAD_CAST "newNode3",BAD_CAST "newNode3 content"); xmlNodePtr node = xmlNewNode(NULL,BAD_CAST "node2"); xmlNodePtr content = xmlNewText(BAD_CAST "NODE CONTENT"); xmlAddChild(root_node,node); xmlAddChild(node,content); xmlNewProp(node,BAD_CAST "attribute",BAD_CAST "yes"); node = xmlNewNode(NULL,BAD_CAST "son"); xmlAddChild(root_node,node); xmlNodePtr grandson = xmlNewNode(NULL,BAD_CAST "grandson"); xmlAddChild(node,grandson); xmlAddChild(grandson,xmlNewText(BAD_CAST "This is a grandson node")); int nRel = xmlSaveFile("CreatedXml.xml",doc); if (nRel != -1) { xmlFreeDoc(doc); return 1; } }
结果为:
<?xml version="1.0"?> <root><newNode1>newNode1 content</newNode1><newNode2>newNode2 content</newNode2><newNode3>newNode3 content</newNode3><node2 attribute="yes">NODE CONTENT</node2><son><grandson>This is a grandson node</grandson></son></root>
4、解析xml的例子
需要解析的xml文件:
<story> <storyinfo> <author>John Fleck</author> <datewritten>June 2,2002</datewritten> <keyword>example keyword</keyword> </storyinfo> <body> <headline>This is the headline</headline> <para>This is the body text.</para> </body> </story>
程序为:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <libxml/xmlmemory.h> #include <libxml/parser.h> void parseStory (xmlDocPtr doc,xmlNodePtr cur) { xmlChar *key,*name; cur = cur->xmlChildrenNode; while (cur != NULL) { if ((!xmlStrcmp(cur->name,(const xmlChar *)"author"))) { name = xmlNodeListGetString(doc,cur->xmlChildrenNode,1); printf("author: %s\n",name); xmlFree(name); } if ((!xmlStrcmp(cur->name,(const xmlChar *)"keyword"))) { key = xmlNodeListGetString(doc,1); printf("keyword: %s\n",key); xmlFree(key); } cur = cur->next; } return; } static void parseDoc(char *docname) { xmlDocPtr doc; xmlNodePtr cur; doc = xmlParseFile(docname); if (doc == NULL ) { fprintf(stderr,"Document not parsed successfully. \n"); return; } cur = xmlDocGetRootElement(doc); if (cur == NULL) { fprintf(stderr,"empty document\n"); xmlFreeDoc(doc); return; } if (xmlStrcmp(cur->name,(const xmlChar *) "story")) { fprintf(stderr,"document of the wrong type,root node != story"); xmlFreeDoc(doc); return; } cur = cur->xmlChildrenNode; while (cur != NULL) { if ((!xmlStrcmp(cur->name,(const xmlChar *)"storyinfo"))) { parseStory (doc,cur); } cur = cur->next; } xmlFreeDoc(doc); return; } int main(int argc,char **argv) { char *docname; docname = "1.xml"; parseDoc (docname); return (1); }