Libxml2解析XML文件
Libxml2是由C语言开发的一个库,除了解析XML文档外,还可以解析HTML文档(不过这我没有研究)。同时,libxml2库可移植于多个平台
大致可与运行在如下平台: Linux, Unix, Windows, CygWin, MacOS, MacOS X, RISC Os, OS/2, VMS, QNX, MVS, VxWorks
可以从官网: http://xmlsoft.org 获取最新版本(2.9.8)的libxml2库。Linux下编译也很简单
./configure
make
make install
官网上也有一些例子,以及API接口文档,常见问题,Tutorial,建议去看看。也可以从下载的源文件目录doc中离线浏览
libxml2库囊括了以下的模块,
Table of Contents
DOCBparser: old DocBook SGML parser
HTMLparser: interface for an HTML 4.0 non-verifying parser
HTMLtree: specific APIs to process HTML tree, especially serialization
SAX: Old SAX version 1 handler, deprecated
SAX2: SAX2 parser interface used to build the DOM tree
c14n: Provide Canonical XML and Exclusive XML Canonicalization
catalog: interfaces to the Catalog handling system
chvalid: Unicode character range checking
debugXML: Tree debugging APIs
dict: string dictionary
encoding: interface for the encoding conversion functions
entities: interface for the XML entities handling
globals: interface for all global variables of the library
hash: Chained hash tables
list: lists interfaces
nanoftp: minimal FTP implementation
nanohttp: minimal HTTP implementation
parser: the core parser module
parserInternals: internals routines and limits exported by the parser.
pattern: pattern expression handling
relaxng: implementation of the Relax-NG validation
schemasInternals: internal interfaces for XML Schemas
schematron: XML Schemastron implementation
threads: interfaces for thread handling
tree: interfaces for tree manipulation
uri: library of generic URI related routines
valid: The DTD validation
xinclude: implementation of XInclude
xlink: unfinished XLink detection module
xmlIO: interface for the I/O interfaces used by the parser
xmlautomata: API to build regexp automata
xmlerror: error handling
xmlexports: macros for marking symbols as exportable/importable.
xmlmemory: interface for the memory allocator
xmlmodule: dynamic module loading
xmlreader: the XMLReader implementation
xmlregexp: regular expressions handling
xmlsave: the XML document serializer
xmlschemas: incomplete XML Schemas structure implementation
xmlschemastypes: implementation of XML Schema Datatypes
xmlstring: set of routines to process strings
xmlunicode: Unicode character APIs
xmlversion: compile-time version informations
xmlwriter: text writing API for XML
xpath: XML Path Language implementation
xpathInternals: internal interfaces for XML Path Language implementation
xpointer: API to handle XML Pointers
因为libxml2包含大量函数,实现有不同的方式。这里介绍一些常用的。至于其他的功能有兴趣自己研究吧……
而这里主要用到的为 parser,tree,xmlreader,xmlwriter 这几个模块
parser/tree
读取XML文档
首先介绍xml文档的解析吧,大致调用函数如下
- xmlReadFile/xmlParseFile 打开一个XML文档并返回一个文档对象指针xmlDocPtr
- xmlDocGetRootElement 获取XML文档的根节点xmlNodePtr
- 获取根节点,以及childNode的名称、属性名/值。而这一步骤可以通过递归实现。
- 最后由 xmlFreeDoc、xmlCleanupParser 释放所有分配的内存
下面给出一个例子(C++)
1 |
|
有如下 test.xml 文档
1 |
|
编译运行 g++ main.cpp -o main xml2-config –libs –cflags
&& ./main test.xml
输出信息
1 |
|
可以看到,成功的解析xml文档并格式化的输出信息。这个例子的核心代码就是那个递归函数。现在我们来看看它到底干了些什么。
不过在此之前,先谈谈 xmlParseFile 和 xmlReadFile 的区别。它们都是打开一个XML文档并返回一个文档对象指针 xmlDocPtr ,不同之处就在于它们提供的参数不同
1 |
|
xmlReadFile 以指定的编码格式打开xml文档,而 xmlParseFile 默认以UTF-8编码格式打开文档。
比如,刚才的test.xml 中通过encoding指定了UTF-8编码格式,那么用 xmlParseFile 能成功解析,用 xmlReadFile 函数无论
const char *encoding 参数为NULL还是“UTF-8” 也能成功解析。
但是 test.xml 只有 那么 xmlParseFile 会解析失败,而 xmlReadFile 只有 第二个参数为 “UTF-8”时才能解析成功。
好了,继续看那个递归函数吧。。。
首先用 xmlNodePtr xmlNodePtr1= _xmlNodePtr->children; 获取的 _xmlNodePtr 节点的所有子节点,然后在while循环中判断每个子节点的类型,xmlNodePtr1->type!=XML_TEXT_NODE 如果不是 XML_TEXT_NODE 那就继续。接着 用 xmlChildElementCount 获取 xmlNodePtr1 节点指针的所有子节点个数,并用一个 ishas_child 标识是否存在子节点,对于存在子节点的节点,就进行递归。然后显示了节点的属性,通过 xmlHasProp 判断是否存在指定名字的属性,存在用 xmlGetProp 获取其值。注意,我获取了 一个属性对象(链表) xmlAttr* xmlAttr1=xmlNodePtr1->properties
之后进行遍历。在libxml2中,xmlNode、xmlDoc、xmlAttr 都是一个链表。
之后进入递归,depth 只是表示深度,用于格式化输出
if(ishas_child){
depth+=10;
ParserXML(depth,xmlNodePtr1);
}
在进入的每个递归函数执行结束之前减去刚才进入的深度
if(depth>0){
depth-=10;
}
接下来就是生成XML文档。。。
生成XML文档
生成就简单一些了,下面是一个例子
1 |
|
这里通用的做法为 xmlNewDoc 创建一个新的XML文档并返回一个 xmlDocPtr ,创建一个根节点就是创建一个 xmlNodePtr 并通过 xmlDocSetRootElement 设置 xmlDocPtr 的根节点为 xmlNodePtr 。之后在继续添加子节点时,只需在 xmlNodePtr 的基础上创建新节点并添加即可。
xmlNewTextChild 函数用于文件一个文本子节点。如 <node>Hello</node>
创建新节点的方法为 xmlNewNode 它返回一个 xmlNodePtr ,之后 xmlAddChild 把一个节点添加到父节点上。
通过 xmlNewProp 创建一个属性 xmlAttrPtr ,之后可通过
xmlSetProp或xmlNodeSetName 设置属性的值。删除属性 xmlRemoveProp
最后,全部OK了, xmlSaveFileEnc 来保存XML文档
编译运行生成test.xml,可能格式有点混乱,我修改了一下
1 |
|
OK,基本上解析XML也不算太难。除了libxml2库外,还有其他的库也可以解析XML。看个人爱好了 😃
bye~
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!