libxml2 使用教程【转】
https://blog.csdn.net/zhoudaxia/article/details/8565731#
本文整理自官方使用教程http://xmlsoft.org/tutorial/index.html。
示例文档story.xml如下:
- <?xml version="1.0"?>
- <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>
1、解析xml文档
解析文档时只需要文档名和一个函数调用,再加上错误处理。下面代码查找keyword节点并打印节点下的文本内容,如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
/* 解析storyinfo节点,打印keyword节点的内容 */
void
(cur != NULL){
- (!xmlStrcmp(cur->name, ( xmlChar *))){
- key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
- ;
- }
- /* 解析文档 */
static parseDoc( *docname){ - (doc == NULL){
- ;
- cur = xmlDocGetRootElement(doc);
- (cur == NULL){
- fprintf(stderr,
;
- (xmlStrcmp(cur->name, ( xmlChar *))){
- ;
- }
- (cur != NULL){
- (!xmlStrcmp(cur->name, ( xmlChar *))){
- }
- }
- ;
- }
- int argc, **argv){
- *docname;
- (argc <= 1){
- 0;
- 1;
- }
解析XML文档的基本流程如下:
(1)定义文档指针和节点指针。
(2)调用xmlParseFile()解析文档。如果不成功,注册一个错误并停止。一个常见错误是不适当的编码。XML标准文档除了用默认的UTF-8或UTF-16外,还可显式指定用其它编码保存。如果文档是这样,libxml2将自动地为你转换到UTF-8。更多关于XML编码信息包含在XML标准中。
(3)调用xmlDocGetRootElement()获取文档根节点,若无根节点则释放文档树并返回。
(4)确认文档是正确的类型,通过检查根节点名称来判断。
(5)检索节点的内容,这需要遍历文档树。对每个节点,遍历其子节点都需要一个循环。先用cur =
cur->xmlChildrenNode获取第一个子节点,然后通过cur =
cur->next不断向前遍历,直到cur==NULL。查找找指定节点时使用xmlStrcmp()函数,如果你指定的名称相同,就找到了你要的节点。通常把查找某个子节点的过程封装成函数。
(6)获取节点中的内容。查找到指定节点后,调用xmlNodeListGetString()获取节点下的文本。注意在XML中,包含在节点中的文本是这个节点的子节点,因此获取的是cur->xmlChildrenNode中的字符串。xmlNodeListGetString()会为返回的字符串分配内存,因此记得要用xmlFree()来释放它。
(7)调用xmlFreeDoc()释放文档树指针。
2、使用XPath查询信息
在xml文档中查询信息是一项核心工作。Libxml2支持使用XPath表达式来查找匹配的节点集。简而言之,XPath之于xml,好比SQL之于关系数据库。要在一个复杂的xml文档中查找所需的信息,XPath简直是必不可少的工具。下面代码查询所有keyword元素的内容。
#include <libxml/parser.h>
#include <libxml/xpath.h>
/* 解析文档 */
*docname){
- xmlDocPtr doc;
- (doc == NULL){
- NULL;
- doc;
- }
- /* 查询节点集 */
- context = xmlXPathNewContext(doc);
- (context == NULL){
- printf(
NULL; - }
- result = xmlXPathEvalExpression(xpath, context);
- (result == NULL){
- NULL;
- (xmlXPathNodeSetIsEmpty(result->nodesetval)){
- xmlXPathFreeObject(result);
- NULL;
- result;
- int argc, ** argv){
- *docname;
- ;
- xmlNodeSetPtr nodeset;
- i;
- (argc <= 1){
- printf(
(0); - }
- (result){
- (i=0; i < nodeset->nodeNr; i++){
- }
- (1);
- }
可以在story.xml中多插入几个keyword元素,然后运行一下本程序看看效果。使用XPath查询信息的基本流程如下:
(1)调用xmlXPathNewContext()给文档树创建一个上下文指针。
(2)调用xmlXPathEvalExpression(),传入XPath表达式和上下文指针,返回一个xmlXPathObjectPtr结果集指针。nodesetval对象包含keyword节点个数(nodeNr)和节点列表(nodeTab)。在使用之前要和xmlXPathNodeSetIsEmpty()检查nodesetval节点列表是否为空。
(3)遍历节点列表nodeTab,用xmlNodeListGetString()获取每个keyword节点的内容。
(4)用xmlXPathFreeObject()释放查询结果,用xmlFreeDoc()释放文档树。
更多关于Xpath的内容可以参考XPath官方规范http://www.w3.org/TR/xpath/。XPath语法的介绍,可参考w3school上的教程http://www.w3school.com.cn/xpath/index.asp,或者http://w3schools.com/xpath/default.asp。只有掌握XPath,才能掌握使用大型XML文件获取信息的方法,否则每寻找一个节点都要从根节点找起,很耗时耗力。
3、修改xml文档
这与上面的过程类似,首先遍历文档树,找到要插入(或删除)的节点处,然后插入(或删除)相关的内容。下面代码在storyinfo节点下插入一个keyword元素。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
void
xmlChar* keyword) {
- xmlNewTextChild(cur, NULL, ( xmlChar*), keyword);
- ;
- }
- char *keyword) {
- (doc == NULL ) {
- (NULL);
- (cur == NULL) {
- fprintf(stderr,
(NULL);
- (xmlStrcmp(cur->name, ( xmlChar *) )) {
- fprintf(stderr,
(NULL);
- (cur != NULL) {
- ((!xmlStrcmp(cur->name, ( xmlChar *)))){
- parseStory (doc, cur, ( xmlChar*)keyword);
- (doc);
- }
- int
int **argv) { - *docname;
- *keyword;
- (argc <= 2) {
- printf(
(0); - }
- (doc != NULL) {
- xmlSaveFormatFile(docname, doc, 0);
- (1);
- }
这里xmlNewTextChild函数在当前节点指针上添加一个子元素。如果希望元素有名字空间,则可以在这里加上。添加完后,就要用xmlSaveFormatFile()把修改后的文档写入到文件。我们这里使用原来doc文档指针,因此会覆盖原来的文件。第三个参数如果设置为1,则输出的文档会自动缩进。
若要删除某个节点,可以使用以下代码:
if)){
- xmlNodePtr tempNode;
- ;
- }
注意libxml2并没有xmlDelNode或者xmlRemoveNode之类的函数。我们需要将当前节点从文档中断链(unlink),文档就不会再包含这个子节点。这样做需要使用一个临时变量来存储断链节点的后续节点,并记得要手动删除断链节点的内存。
若要给节点添加属性,可以这样:
xmlDocPtr
- parseDoc( *docname, *uri) {
- (doc == NULL ) {
- fprintf(stderr,
(NULL); - }
- (cur == NULL) {
- fprintf(stderr,
(NULL);
- (xmlStrcmp(cur->name, ( xmlChar *) )) {
- fprintf(stderr,
(NULL);
- , NULL);
- newattr = xmlNewProp(newnode, , uri);
- (doc);
- }
我们用xmlAttrPtr声明一个属性指针。在找到story元素后,用xmlNewTextChild()新建一个reference子元素,用xmlNewProp()给这个子元素新建一个uri属性。文档修改完后要用xmlSaveFormatFile()写入到磁盘。
查询属性的过程类似。如下:
void
(cur != NULL) {
- ((!xmlStrcmp(cur->name, ( xmlChar *)))) {
- );
- printf(
;
- }
关键函数为xmlGetProp(),用来获取节点中的指定属性。注意如果你使用DTD为属性声明一个固定的或默认的值,则该函数也查找这些值。
4、创建xml文档
有了上面的基础,创建一个xml文档显得非常简单,就是一个不断插入节点的过程。其流程如下:
(1)用xmlNewDoc函数创建一个文档指针doc;
(2)用xmlNewNode函数创建一个节点指针root_node;
(3)用xmlDocSetRootElement将root_node设置为doc的根结点;
(4)用xmlAddChild()给root_node添加一系列的子节点,并设置子节点的内容和属性;
(5)用xmlSaveFile将xml文档存入文件;
(6)用xmlFreeDoc函数关闭文档指针,并清除本文档中所有节点动态申请的内存。
下面代码创建一个xml文档:
#include <stdio.h>
#include <iostream>
#include <libxml/parser.h>
#include <libxml/tree.h>
using std;
- int argc, * argv[]){
- );
- xmlNodePtr root_node=xmlNewNode(NULL,BAD_CAST);
- xmlDocSetRootElement(doc,root_node);
- xmlNewTextChild(root_node, NULL, BAD_CAST, BAD_CAST
, BAD_CAST
, BAD_CAST - xmlNodePtr node=xmlNewNode(NULL, BAD_CAST);
- ,BAD_CAST);
- node=xmlNewNode(NULL,BAD_CAST);
- );
- nRel=xmlSaveFile(,doc);
- (nRel!=-1){
- cout<<<<nRel<<<<endl;
- 1;
- }
编译并运行这个程序,将创建CreatedXml.xml文档,内容如下:
<>
>>
>>
>>
=>>
>
>>
>
</>
注意,有多种方式可以添加子节点。第一是用xmlNewTextChild直接添加一个文本子节点;第二是先创建新节点,然后用xmlAddChild将新节点加入上层节点。
5、编码转换
数据编码兼容性问题是很多开发人员都会遇到的一大难题,特别是在使用libxml时。libxml内部使用UTF-8格式存储和操作数据。你的应用程序数据如果使用其他格式的编码,例如ISO-8859-1编码,则在传给libxml之前必须转换成UTF-8格式。如果你的应用输出想用非UTF-8格式的编码,也需要进行转换。
Libxml2本身只支持把UTF-8,
UTF-16和ISO-8859-1格式的外部数据转换成内部使用的UTF-8格式,以及处理完后输出成这些格式的数据。对其他的字符编码,需要使用libiconv(当然你也可以使用其他的国际化库,例如ICU)。当前libiconv支持150多种不同的字符编码,libiconv的实现尽量保证支持所有我们听过的编码格式。在使用libxml之前,一般是通过libiconv把数据先转换UTF-8格式。在使用libxml处理完之后,再通过libiconv把数据输出成你要的编码格式。
一个常见的错误是一份代码的不同部分的数据使用不同的编码格式。例如内部数据使用ISO-8859-1格式的应用程序,联合使用libxml,而它的内部数据格式为UTF-8。这样应用程序在运行不同的代码段时要不同地对待内部数据,这有可能导致解析数据出现错误。
例子1:使用Libxml内建的编码处理器
下面的例子创建一个简单的文档,添加从命令行得到的数据到文档根元素,并以合适的编码格式输出到stdout。对提供的数据我们使用ISO-8859-1编码,处理过程为从ISO-8859-1到UTF-8,再到ISO-8859-1。命令行上输入的字符串从ISO-8859-1格式转换成UTF-8格式,以供libxml使用,输出时又重新转换成ISO-8859-1格式。
#include <string.h>
#include <libxml/parser.h>
/* 对指定编码格式的外部数据,转换成libxml使用UTF-8格式 */
*
- convert(unsigned *in, *encoding){
- *out;
- ret,size,out_size,temp;
- xmlCharEncodingHandlerPtr handler;
- )strlen(( *)in)+1;
- out = (unsigned *)malloc(()out_size);
- (out) {
- handler = xmlFindCharEncodingHandler(encoding);
- (!handler) {
- free(out);
- (out) {
- (ret || temp-size+1) {
- (ret) {
- printf(
{ - printf(
{
- *)realloc(out,out_size+1);
- out[out_size]=0;
- {
- printf(
(out);
- int
int **argv) { - *content, *out;
- xmlDocPtr doc;
- *encoding = ;
- (argc <= 1) {
- (0);
- *)argv[1];
- );
- xmlChar*), out);
- xmlDocSetRootElement(doc, rootnode);
- xmlSaveFormatFileEnc(, doc, encoding, 1);
- (1);
- }
编译运行这个程序,假设在命令行上提供的数据"zhou"是ISO-8859-1格式(我的系统中不是),则输出文档为:
<? = =?>
<></>
编码转换的基本流程如下:
(1)用xmlCharEncodingHandlerPtr定义一个编码处理器指针,用xmlFindCharEncodingHandler()查找libxml2中指定的编码处理器。libxml2内建只支持把UTF-8,
UTF-16和ISO-8859-1格式的外部数据转换成内部使用的UTF-8格式。如果要转换其他格式的数据(如中文编码),则要使用独立的libiconv库给libxml2注册新编码处理器。
(2)调用编码处理器的input()函数,把外部数据转换成libxml2使用的格式。
(3)进行xml处理,处理完若要保存成非UTF-8格式的文档,使用xmlSaveFormatFileEnc()函数。若保存的编码格式libxml2不支持,则只能用libiconv把保存的文档转换成需要的编码格式。
例子2:通过iconv库给Libxml注册新的编码处理器
下面例子先编写GBK的编码处理器gbk_input()和gbk_output(),前者是GBK到UTF-8输入处理,后者是UTF-8到GBK输出处理,这两个处理器都要用到iconv转换函数。然后调用xmlNewCharEncodingHandler()注册输入输出处理器。对输入输出数据的编码转换由convertToUTF8From()和utf8ConvertTo()来完成,它们都是调用xmlFindCharEncodingHandler()查找已注册的处理器,然后在处理器上调用input()或output()对数据进行编码转换。
#include <string.h>
#include <iconv.h>
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>
#include <libxml/xmlreader.h>
/* 输入编码处理器:GBK到UTF-8 */
int *out, *outlen,
- unsigned *in, *inlen){
- *outbuf = ( *) out;
- *inbuf = ( *) in;
- len1, len2, rslt;
- 这在32位平台下是正常的,但到了64平台下size_t为64位,
- 那(size_t*)inlen将是一个未知的数据
- iconv_from = iconv_open(,);
- rslt = iconv(iconv_from, &inbuf, &len1, &outbuf, &len2);
- (rslt < 0){
- rslt;
- *) outbuf - out);
- *inlen = ((unsigned *) inbuf - in);
- *outlen;
- }
- /* 输出编码处理器:UTF-8到GBK */
int *out, *outlen, - unsigned *in, *inlen){
- *outbuf = ( *) out;
- *inbuf = ( *) in;
- iconv_t iconv_to;
- len1, len2, rslt;
- 这在32位平台下是正常的,但到了64平台下size_t为64位,
- */
- ,);
- (rslt < 0){
- rslt;
- }
- *outlen = ((unsigned *) outbuf - out);
- *) inbuf - in);
- *outlen;
- /**
- * 把encoding编码的输入数据in转换成utf-8格式返回
- */
*in, *encoding){ - ret;
- size;
- out_size;
- temp;
- xmlCharEncodingHandlerPtr handler;
- (in == 0)
- 0;
- handler = xmlFindCharEncodingHandler(encoding);
- (!handler) {
- printf(
); - 0;
- )strlen(in) + 1;
- *) xmlMalloc(() out_size);
- memset(out, 0, out_size);
- (out != NULL) {
- xmlChar *) in, &temp);
- (ret || temp - size + 1) {
- (ret){
- printf(
{ - printf(
- {
- *) xmlRealloc(out, out_size + 1);
- out[out_size] = 0;
- {
- out;
- }
- /**
- * utf8ConvertTo:
- * 出错则返回NULL
- char *encoding){
- *out;
- ret;
- size;
- out_size;
- temp;
- (in == 0)
- 0;
- (!handler) {
- );
- 0;
- }
- ) strlen((*)in) + 1;
- out = ( *) malloc(() out_size);
- (out != NULL) {
- xmlChar *) in, &temp);
- (ret || temp - size + 1){
- (ret){
- printf(
{ - printf(
{
- *) realloc(out, out_size + 1);
- out[out_size] = 0;
- {
- out;
- int argc, **argv){
- *content;
- (argc <= 1) {
- printf(
(0); - }
- *)argv[1];
- xmlNewCharEncodingHandler(, gbk_input, gbk_output);
- xmlNewCharEncodingHandler(, gbk_input, gbk_output);
- );
- );
- rootnode = xmlNewDocNode(doc, NULL, ( xmlChar*), out);
- , doc, , 1);
- (1);
- }
这个例子在32位与64位Linux平台下测试通过。iconv库是Linux默认自带的组件,因此在Linux中使用libxml非常方便。我们先建立utf-8编码与gbk编码的转换接口,并将接口插入到libxml2库中,这样xml库就支持对gb2312和gbk编码的支持了。当然,这个转换不会自动完成,我们需要使用从libxml库中查找特定编码的接口,libxml支持一些基本的编码接口,如ISO-8859-1,UTF-16等编码,但不支持gbk,所以在上述代码中,我们定义了gbk_input,与gbk_output两个接口,这两个接口的原型声明是libxml库的标准声明,即xmlCharEncodingInputFunc和xmlCharEncodingOutputFunc。在使用完libxml库之后,我们需要释放libxml库的转换资源。
例子3:直接使用iconv库进行转换
下面例子直接使用iconv函数对输入输出进行编码转换,而不是通过注册编码处理器的方式。
#include <stdio.h>
#include <string.h>
#include <iconv.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
/* 代码转换:从一种编码转为另一种编码 */
int *from_charset, *to_charset,
- *inbuf, inlen,
- * outbuf, outlen){
- len1, len2, rslt;
- 这在32位平台下是正常的,但到了64平台下size_t为64位,
- 那(size_t*)inlen将是一个未知的数据
- cd = iconv_open(to_charset,from_charset);
- (cd == 0)
- -1;
- (rslt== -1)
- -1;
- 0;
- /* GB2312转换为UTF-8
- * 成功则返回一个动态分配的char*变量,需要在使用完毕后手动free,失败返回NULL
- char *inbuf){
- nOutLen = 2*strlen(inbuf)-1;
- *szOut=(*)xmlMalloc(nOutLen);
- (-1 == encoding_convert(,,inbuf,strlen(inbuf),szOut,nOutLen)){
- szOut;
- /* UTF-8转换为GB2312
- */
char *inbuf){ - nOutLen = 2* strlen(inbuf)-1;
- *szOut=(*)xmlMalloc(nOutLen);
- (-1 == encoding_convert(,,inbuf,strlen(inbuf),szOut,nOutLen)){
- xmlFree(szOut);
- szOut;
- }
- int argc, **argv){
- xmlDocPtr doc = xmlNewDoc(BAD_CAST );
- );
- *szOut=gb2312_utf8();
- xmlNewTextChild(root_node, NULL, BAD_CAST , BAD_CAST
, BAD_CAST
, BAD_CAST
,BAD_CAST szOut); - xmlFree(szOut);
- );
- xmlNodePtr content = xmlNewText(BAD_CAST
);
- xmlNewProp(node,BAD_CAST ,BAD_CAST szOut);
- szOut = gb2312_utf8();
- nRel = xmlSaveFormatFileEnc(,doc,,1);
- (nRel != -1){
- , nRel);
- }
- 1;
- }
这个例子中,当把中文数据写入到XML节点时,使用gb2312_utf8()直接转换成UTF-8格式,这种直接通过iconv转换的方式更高效。编译并运行程序,输出文档如下:
<? = =?>
<>
>>
>>
>>
></>
=>>
中文节点content of chinese node中文节点
- </>
6、一个真实的例子
内容整理自http://xmlsoft.org/example.html。
下面是一个真实的例子。应用程序数据的内容不使用DOM树,而是使用内部数据结构来保存。这是一个基于XML存储结构的数据库,它保存了与Gnome相关的任务。如下:
<? =?>
< =>
>
>
=/>
></>
></>
>
></>
>>
>>
>
>
>
>
>
>
>>
></>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
</>
把XML文件加载到一个内部DOM树中只是调用几个函数的问题,而遍历整个树来收集数据,并生成内部结构则更困难,也更容易出错。
对输入结构的定义法则是非常宽松的。属性的顺序无关紧要(XML规范清楚地说明了这一点),不要依赖于一个节点的子节点顺序通常是一个好的主意,除非这样做真的使事情变得更困难了。下面是解析person信息的一段代码:
/*
- */
typedef person { - *name;
- *email;
- *company;
- *organisation;
- *smail;
- *webPage;
- *phone;
- } person, *personPtr;
- /*
- * 解析person的代码
- "parsePerson\n"
* 为结构分配内存
- */
(person)); - (ret == NULL) {
- fprintf(stderr,
(NULL); - }
- (person));
- cur = cur->xmlChildrenNode;
- (cur != NULL) {
- ((!strcmp(cur->name, )) && (cur->ns == ns))
- ((!strcmp(cur->name, )) && (cur->ns == ns))
- (ret);
- }
下面是要注意的一些事项:
(1)通常一个递归的解析风格是更方便的:XML数据天然地遵循重复式地构造,并且是高度结构化的。
(2)两个参数是xmlDocPtr和xmlNsPtr类型,即指向XML文档和应用程序保留的命名空间的指针。文档信息非常广泛,为你的应用程序数据集定义一个命名空间并测试元素和属性是否属性这个空间是一个好的编程实践。这只需一个简单的相等测试(cur->ns
== ns)。
(3)为了查询文本和属性值,你可以使用函数xmlNodeListGetString()来获取所有文本,和由DOM输出生成的引用节点,并生成一个单一的文本字符串。
下面是解析另外一个结构的代码片段:
#include <libxml/tree.h>
/*
- * 一个Job的描述
- typedef job {
- *projectID;
- *application;
- *category;
- nbDevelopers;
- } job, *jobPtr;
- /*
- * 解析Job的代码
- "parseJob\n"
* 为结构分配内存
- */
(job)); - (ret == NULL) {
- fprintf(stderr,
(NULL); - }
- (job));
- cur = cur->xmlChildrenNode;
- (cur != NULL) {
- ((!strcmp(cur->name, )) && (cur->ns == ns)) {
- ret->projectID = xmlGetProp(cur, );
- (ret->projectID == NULL) {
- fprintf(stderr,
((!strcmp(cur->name, )) && (cur->ns == ns))
- ret->application = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
- ((!strcmp(cur->name, )) && (cur->ns == ns))
- ret->category = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
- ((!strcmp(cur->name, )) && (cur->ns == ns))
- ret->contact = parsePerson(doc, ns, cur);
- (ret);
- }
一旦你会使用libxml2,编写这种类型的代码是非常简单的,也很无趣。最终,你可以写一个拥有C数据结构和一组XML文档例子或一个XML DTD的桩模块,并生成在C数据和XML存储之间导入和导出数据的代码。
7、详细代码示例
对Libxml2更详细的使用介绍,可参考官方的详细代码示例http://xmlsoft.org/examples/index.html。上面提供了Libxml2各个组件怎么使用的详细代码示例,包括以下部分:
xmlWriter: 测试xmlWriter的各个API,包括写入到文件、写入到内存缓冲区、写入到新的文档或子树、字符串编码转换、对输出文档进行序列化。
InputOutput: 演示使用xmlRegisterInputCallbacks来建立一个客户I/O层,这被用在XInclude方法上下文中,以显示怎样构建动态文档。还演示使用xmlDocDumpMemory来输出文档到字符缓冲区中。
Parsing: 演示使用xmlReadMemory()读取XML文档,xmlFreeDoc()释放文档树;使用xmlCreatePushParserCtxt()和xmlParseChunk()一块一块地读取XML文档到文档树中。演示为XML文档创建一个解析上下文,然后解析并验证这个文档;创建一个文档树,检查并验证结果,最后用xmlFreeDoc()释放文档树。演示使用xmlReadFile()读取XML文档并用xmlFreeDoc()释放它。
Tree: 演示怎样创建文档和节点,并把数据dump到标准输出或文件中。演示使用xmlDocGetRootElement()获取根元素,然后遍历文档并打印各个元素名。
XPath: 演示怎样计算XPath表达式,并在XPath上下文注册名称空间,打印结果节点集。演示怎么加载一个文档、用XPath定位到某个子元素、修改这个元素并保存结果。这包含了加载/编辑/保存的一个完整来回。
xmlReader: 演示使用xmlReaderForFile()解析XML文档,并dump出节点的信息。演示在用xmlReaderForFile()解析时验证文档的内容,激活各种选项,诸如实体替换、DTD属性不一致等。演示使用xmlTextReaderPreservePattern()提取XML文档中某一部分的子文档。演示重用xmlReader对象来解析多个XML文档。
libxml2 使用教程【转】的更多相关文章
- CM12.1/13.0编译教程
环境搭建 1.安装64位Ubuntu系统(实体安装.虚拟机安装均可) 注意:要求机器至少4G内存(虚拟机至少分配4G内存),硬盘至少100G空间(源码20G+,编译后整个目录约60~70G) 安装方法 ...
- LNMP编译安装教程
LNMP编译安装教程 此次安装在Centos上,我采用的CentOS的版本是:CentOS release 6.5 (Final) 可以通过以下命令查看:lsb_release -a 一.准备工作: ...
- CM12同步源码及编译教程
同时提供基于安卓5.0的MKL魔趣猪扒饭编译教程~[玩机组出品]魔趣猪扒饭MKL50.1编译教程http://www.oneplusbbs.com/forum.php?mod=viewthread&a ...
- Python实用工具包Scrapy安装教程
对于想用每个想用Python开发网络爬虫的开发者来说,Scrapy无疑是一个极好的开源工具.今天安装之后觉得Scrapy的安装确实不易啊.所以在此博文一篇,往后来着少走弯路. 废话不多说了,如果 ...
- Lamp环境的详细安装教程
原文:Lamp环境的详细安装教程 架构LAMP环境 1.布置LAMP环境之前的准备工作 在架构LAMP环境时,确保你的Linux系统已经安装了make.gcc.gcc-c++(使用rpm -q xxx ...
- LAMP环境搭建教程
原文:LAMP环境搭建教程 学习PHP脚本编程语言之前,必须先搭建并熟悉开发环境,开发环境有很多种,例如LAMP.WAMP.MAMP等.这里我介绍一下LAMP环境的搭建,即Linux.Apache.M ...
- C++的XML编程经验――LIBXML2库使用指南[转]
C++的XML编程经验――LIBXML2库使用指南 写这篇文章的原因有如下几点:1)C++标准库中没有操作XML的方法,用C++操作XML文件必须熟悉一种函数库,LIBXML2是其中一种很优秀的XML ...
- C的xml编程-libxml2(转)
这里主要讲述libxml2在linux下的使用. (以下内容除了linux下的安装步骤是自己写的,其余均出自http://www.blogjava.net/wxb_nudt/archive/2007/ ...
- Nginx安装配置PHP(FastCGI)环境的教程
这篇是Nginx安装配置PHP(FastCGI)环境的教程.Nginx不支持对外部程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用. 一.什么是 FastCGI F ...
随机推荐
- odoo导入功能二开
原来有的导入功能相信很多小伙伴对其功能不是很满意,不过没关系,我们可以二开啊,把它的功能改造成你想要的样子,接下来让我们看看怎么办吧 例如我想把员工导入功能中添加上用户同步注册功能 首先,我要找到原模 ...
- Plant Simulation常用命令
Plant Simulation 是面向对象的三维离散事件仿真软件,使您能够快速.直观地构建逼真的物流模型. 您还可以使用高级统计工具执行复杂的生产分析.以下介绍该软件的一些常用命令. 1. clea ...
- JDBC之批处理
JDBC之批处理 现在有这么一个需求,要求把2000条记录插入表中,如果使用java代码来操作,我们可以使用Statement或者PreparedStatement来实现,通过循环来把SQL语句一条又 ...
- EditText 数字范围 检查string 是不是数字
public static boolean isNumeric00(String str){ try{ Integer.parseInt(str); return true; }catch(Numbe ...
- Java可视化编程---SendMail工具的开发
介绍: SendMail是一款简便的163邮箱发件工具 利用了163的SMTP接口来发送邮件 版本号:SendMail v1.0 在编写发送邮件工具之前,还需要安装 JavaMail API 和Jav ...
- NOI.AC NOIP模拟赛 第四场 补记
NOI.AC NOIP模拟赛 第四场 补记 子图 题目大意: 一张\(n(n\le5\times10^5)\)个点,\(m(m\le5\times10^5)\)条边的无向图.删去第\(i\)条边需要\ ...
- Linux学习笔记01—安装LInux系统
1.首先,使用光驱或U盘或你下载的Linux ISO文件进行安装. 界面说明: Install or upgrade an existing system 安装或升级现有的系统 install sys ...
- java并发基础(四)--- 取消与中断
<java并发编程实战>的第7章是任务的取消与关闭.我觉得这一章和第6章任务执行同样重要,一个在行为良好的软件和勉强运行的软件之间的最主要的区别就是,行为良好的软件能很完善的处理失败.关闭 ...
- FireDAC 下的 Sqlite [11] - 关于批量提交 SQL 命令的测试
可把下面代码直接贴在空白窗体上, 以快速完成窗体设计: object DBGrid1: TDBGrid Left = 0 Top = 0 Width = 265 Height = 338 Align ...
- 使用CefSharp在.Net程序中嵌入Chrome浏览器(九)——性能问题
在使用CEF的过程中,我发现了一个现象:WPF版的CEF比Chrome性能要差:一些有动画的地方会掉帧(例如,CSS动画,全屏图片拖动等),视频播放的效果也没有Chrome流畅. 查了一下相关资料,发 ...