[libxml2]_[C/C++]_[高效读取XML大文件]

本文介绍如何利用libxml2库高效解析大型XML文件,避免因文件错误导致整体解析失败的问题。通过采用SAX方式读取,即使遇到错误也能继续处理已读取的部分,减少资源浪费。

场景

1.一个比较大的XML文件, 要读进内存里,并转换为相应的对象(比如一个C++对象), 通常都是把整个XML文件读入转换为DOM对象, 之后对DOM对象进行枚举分析生成C++对象.

2.如果这个庞大的XML文件有错误, 那么读取也会失败,即生成DOM失败,这样已经读取过的DOM对象就会被浪费, 造成无法分析XML对象.

说明

1.在生成DOM对象后, 再转换为C++对象,这样就会有两份重复的内存数据,事实上只应该存在一份数据, 而不应该多浪费一份内存. 而且便利庞大的DOM对象也是很费资源,而且XML文件很大时,耗费时间也很多.

2.使用libxml2的xmlTextReader(SAX?)读取, 却可以读取发生错误前的数据.

3.使用系统自带的IO函数, 能方便进行特定文件的分析处理,比如权限限制的文件,比如网络文件.

4.注意,在使用libxml2库是,一定要在主进程的主线程调用初始化xmlInitParser()和结束进程前主线程释放xmlCleanupParser().

例子


#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlreader.h>
#include <iostream>

int pXmlInputReadCallback (void * context, char * buffer, int len)
{
    FILE* file = (FILE*)context;
    int readed = fread(buffer,1,len,file); // 注意, 必须是len个1字节, 这样才能返回准确的readed字节数.
    return readed;
}

int pXmlInputCloseCallback (void * context)
{
    FILE* file = (FILE*)context;
    return fclose(file);
}

/**
 * processNode:
 * @reader: the xmlReader
 *
 * Dump information about the current node
 */
static void
processNode(xmlTextReaderPtr reader) {
    const xmlChar *name, *value;

    name = xmlTextReaderConstName(reader);
    if (name == NULL)
    name = BAD_CAST "--";

    value = xmlTextReaderConstValue(reader);

    printf("%d %d %s %d %d", 
        xmlTextReaderDepth(reader),
        xmlTextReaderNodeType(reader),
        name,
        xmlTextReaderIsEmptyElement(reader),
        xmlTextReaderHasValue(reader));
    if (value == NULL)
    printf("\n");
    else {
        if (xmlStrlen(value) > 40)
            printf(" %.40s...\n", value);
        else
        printf(" %s\n", value);
    }
}

// http://xmlsoft.org/examples/reader1.c
void TestTreeRead()
{
    FILE* file = _wfopen(L"test.xml",L"rb");
    if(!file)
        return;

    xmlTextReaderPtr reader = xmlReaderForIO(pXmlInputReadCallback,pXmlInputCloseCallback,file,NULL,"UTF-8",XML_PARSE_RECOVER);
    if(!reader)
        return;

    int ret = xmlTextReaderRead(reader);
    
    while (ret == 1) {
        processNode(reader);
        ret = xmlTextReaderRead(reader);
    }

    xmlTextReaderClose(reader);
}

部分输出:

0 1 ROOT 0 0
1 1 one 0 0
2 14 #text 0 1

2 1 node1 0 0
3 3 #text 0 1 content of node 1
2 15 node1 0 0
2 14 #text 0 1

2 1 node2 1 0
2 14 #text 0 1

2 1 node3 0 0
3 3 #text 0 1 this node has attributes
2 15 node3 0 0
2 14 #text 0 1

2 1 node4 0 0
3 3 #text 0 1 other way to create content (which is al...
2 15 node4 0 0
2 14 #text 0 1

1 15 one 0 0
1 1 one 0 0
2 14 #text 0 1

2 1 node1 0 0
3 3 #text 0 1 content of node 1
2 15 node1 0 0
2 14 #text 0 1

2 1 node2 1 0
2 14 #text 0 1

2 1 node3 0 0
3 3 #text 0 1 this node has attributes
2 15 node3 0 0
2 14 #text 0 1

2 1 node4 0 0
3 3 #text 0 1 other way to create content (which is al...
2 15 node4 0 0
2 14 #text 0 1

1 15 one 0 0
1 1 one 0 0
2 14 #text 0 1

2 1 node1 0 0
3 3 #text 0 1 content of node 1
2 15 node1 0 0
2 14 #text 0 1

2 1 node2 1 0
2 14 #text 0 1

2 1 node3 0 0
3 3 #text 0 1 this node has attributes
2 15 node3 0 0
2 14 #text 0 1

2 1 node4 0 0
3 3 #text 0 1 other way to create content (which is al...
2 15 node4 0 0
2 14 #text 0 1

参考

1.reader1.c: Parse an XML file with an xmlReader
2.tree2.c: Creates a tree
3.Libxml2 set of examples
4.使用libxml2读取分析xml文件
5.使用libxml2读取内存的xml片段
6.使用libxml2生成文件xhtml
7.关于通过.dll.a生成.lib文件的方法

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白行峰 (花名)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值