掌握了ACMXML库解析XML文件的方法后,下面来实现一个比较完整的程序。

定义基本结构

xml文件格式如下

<?xml version="1.0"?>
<root version="9" count="3" >
    <file id="1">D:\test1.txt</file>
    <file id="2">D:\test2.txt</file>
    <file id="3">D:\test3.txt</file>
</root>

这个xml文件虽然短小,但是对于示例程序来说已经足够了。

xml文件解析后,要将解析的数据保存起来,可以定义这样两个结构:

//对应xml文件的根节点
typedef struct _ROOT
{
    //版本号
    int version;
    //子项的数量
    int count;
} ROOT;

//对应xml文件的子项
typedef struct _FILE
{
    int id;
    //文件路径
    string path;
} ROOT_FILE;

通过宏定义来指定每个节点的名字:

#define XML_ROOT    "root"
#define XML_FILE    "file"
#define XML_ID        "id"
#define XML_VER        "version"
#define XML_COUNT    "count"

定义并实现两个类xml_handler、xml_parser。

xml_parser负责解析xml文件,但是它并不关心xml文件中的数据按什么样的格式保存。

而和具体的格式相关的类为xml_handler,解析xml文件后的数据会保存在这个类的实例里面。

xml_hanlder主要方法介绍

通过startElement和characters两个方法来获取数据:

virtual void startElement( const ACEXML_Char *namespaceURI, const ACEXML_Char *localName, const ACEXML_Char *qName, ACEXML_Attributes *atts )
{
    //file节点
    if(stricmp(localName, XML_FILE) == 0)
    {
        if(root_.count == files_.size())
        {
            return;
        }
        flag_ = FLAG_FILE;
        ROOT_FILE* file = new ROOT_FILE();
        files_.push_back(file);
        for(int i=0; i<atts->getLength(); ++i)
        {
            const char* qname = atts->getQName(i);
            if(stricmp(qname, XML_ID) == 0)
            {
                file->id = atoi(atts->getValue(i));
            }
        }
    }
    //root节点
    else if(stricmp(localName, XML_ROOT) == 0)
    {
        flag_ = FLAG_ROOT;
        for(int i=0; i<atts->getLength(); ++i)
        {
            const char* qname = atts->getQName(i);
            if(stricmp(qname, XML_VER) == 0)
            {
                root_.version= atoi(atts->getValue(i));
            }
            else if(stricmp(qname, XML_COUNT) == 0)
            {
                root_.count = atoi(atts->getValue(i));
            }
        }
    }
    
}


virtual void characters( const ACEXML_Char *ch, size_t start, size_t length )
{
    if(flag_ == FLAG_FILE)
    {
        files_[files_.size() - 1]->path = ch;
    }
    flag_ = FLAG_NULL;
}

通过flush方法将root、file信息写入到xml文件中:

//将当前root、file信息写入到xml文件中
bool flush() const
{
    ofstream ofs(filepath_.c_str(), ios_base::trunc);
    if(!ofs)
    {
        return false;
    }
    ofs << "<?xml version=\"1.0\"?>" << endl;
    ofs << "<" << XML_ROOT << " " << XML_VER << "=\"" << root_.version << "\" " << XML_COUNT << "=\"" << root_.count << "\" >" << endl;
    for(size_t i=0; i<files_.size(); ++i)
    {
        ofs << "\t<" << XML_FILE << " " << XML_ID << "=\"" << files_[i]->id << "\" >" << files_[i]->path << "</" << XML_FILE << ">" << endl;
    }
    ofs << "</" << XML_ROOT << ">" << endl;
    ofs.close();
    return true;
}

通过重载操作符operator[]方法获得子项的数据:

//获取第index个ROOT_FILE子项
//如果index超出当前子项的个数,则返回0
const ROOT_FILE* operator[](size_t index) const
{
    if(index >= files_.size())
    {
        return 0;
    }
    return files_[index];
}

xml_handler完整代码展示

#pragma once

#include "ACEXML/common/DefaultHandler.h"
#include <string>
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;

//对应xml文件的根节点
typedef struct _ROOT
{
    //版本号
    int version;
    //子项的数量
    int count;
} ROOT;

//对应xml文件的子项
typedef struct _FILE
{
    int id;
    //文件路径
    string path;
} ROOT_FILE;

#define XML_ROOT    "root"
#define XML_FILE    "file"
#define XML_ID        "id"
#define XML_VER        "version"
#define XML_COUNT    "count"

//针对某个具体的xml文件格式进行解析的类
//注意:此对象不提供多进程或多线程按序访问的功能
class xml_handler : public ACEXML_DefaultHandler
{
public:
    //构造。
    //@param name 字符串,输入,xml文件的路径
    xml_handler(char* path): filepath_(path), flag_(0) {}
    virtual ~xml_handler(){
        for(size_t i=0; i<files_.size(); ++i)
        {
            if(files_[i])
            {
                delete files_[i];
                files_[i] = 0;
            }
        }
        files_.clear();
    }
    //获取xml文件的路径
    const string& path() const
    {
        return filepath_;
    }
    //获取子项的数量,对应root.count
    const size_t count() const
    {
        return files_.size();
    }
    //获取第index个ROOT_FILE子项
    //如果index超出当前子项的个数,则返回0
    const ROOT_FILE* operator[](size_t index) const
    {
        if(index >= files_.size())
        {
            return 0;
        }
        return files_[index];
    }
    //获取root信息
    const ROOT& root() const
    {
        return root_;
    }
    //增加一个子项
    //@param path 字符串,输入,文件的路径
    //@param id 整形,输入,文件id
    bool increase(const char* path, size_t id)
    {
        if(!path || *path == 0 || id == 0)
        {
            return false;
        }
        ROOT_FILE* file = new(std::nothrow)ROOT_FILE();
        //申请内存失败
        if(!file)
        {
            return false;
        }
        file->path = path;
        file->id = id;
        files_.push_back(file);
        return true;
    }
    //将当前root、file信息写入到xml文件中
    bool flush() const
    {
        ofstream ofs(filepath_.c_str(), ios_base::trunc);
        if(!ofs)
        {
            return false;
        }
        ofs << "<?xml version=\"1.0\"?>" << endl;
        ofs << "<" << XML_ROOT << " " << XML_VER << "=\"" << root_.version << "\" " << XML_COUNT << "=\"" << root_.count << "\" >" << endl;
        for(size_t i=0; i<files_.size(); ++i)
        {
            ofs << "\t<" << XML_FILE << " " << XML_ID << "=\"" << files_[i]->id << "\" >" << files_[i]->path << "</" << XML_FILE << ">" << endl;
        }
        ofs << "</" << XML_ROOT << ">" << endl;
        ofs.close();
        return true;
    }
    //将当前root、file信息输出到控制台
    void dump() const
    {
        cout << "<?xml version=\"1.0\"?>" << endl;
        cout << "<" << XML_ROOT << " " << XML_VER << "=\"" << root_.version << "\" " << XML_COUNT << "=\"" << root_.count << "\" >" << endl;
        for(size_t i=0; i<files_.size(); ++i)
        {
            cout << "\t<" << XML_FILE << " " << XML_ID << "=\"" << files_[i]->id << "\" >" << files_[i]->path << "</" << XML_FILE << ">" << endl;
        }
        cout << "</" << XML_ROOT << ">" << endl;
    }

public:

    virtual void characters( const ACEXML_Char *ch, size_t start, size_t length )
    {
        if(flag_ == FLAG_FILE)
        {
            files_[files_.size() - 1]->path = ch;
        }
        flag_ = FLAG_NULL;
    }

    virtual void endDocument( void )
    {
    }

    virtual void endElement( const ACEXML_Char *namespaceURI, const ACEXML_Char *localName, const ACEXML_Char *qName )
    {
        
    }

    virtual void endPrefixMapping( const ACEXML_Char *prefix )
    {
    }

    virtual void ignorableWhitespace( const ACEXML_Char *ch, int start, int length )
    {
    }

    virtual void processingInstruction( const ACEXML_Char *target, const ACEXML_Char *data )
    {
    }

    virtual void setDocumentLocator( ACEXML_Locator *locator )
    {
        locator_ = locator;
    }

    virtual void skippedEntity( const ACEXML_Char *name )
    {
    }

    virtual void startDocument( void )
    {
    }

    virtual void startElement( const ACEXML_Char *namespaceURI, const ACEXML_Char *localName, const ACEXML_Char *qName, ACEXML_Attributes *atts )
    {
        //file节点
        if(stricmp(localName, XML_FILE) == 0)
        {
            if(root_.count == files_.size())
            {
                return;
            }
            flag_ = FLAG_FILE;
            ROOT_FILE* file = new ROOT_FILE();
            files_.push_back(file);
            for(int i=0; i<atts->getLength(); ++i)
            {
                const char* qname = atts->getQName(i);
                if(stricmp(qname, XML_ID) == 0)
                {
                    file->id = atoi(atts->getValue(i));
                }
            }
        }
        //root节点
        else if(stricmp(localName, XML_ROOT) == 0)
        {
            flag_ = FLAG_ROOT;
            for(int i=0; i<atts->getLength(); ++i)
            {
                const char* qname = atts->getQName(i);
                if(stricmp(qname, XML_VER) == 0)
                {
                    root_.version= atoi(atts->getValue(i));
                }
                else if(stricmp(qname, XML_COUNT) == 0)
                {
                    root_.count = atoi(atts->getValue(i));
                }
            }
        }
        
    }

    virtual void startPrefixMapping( const ACEXML_Char *prefix, const ACEXML_Char *uri )
    {
    }

    virtual void notationDecl( const ACEXML_Char *name, const ACEXML_Char *publicId, const ACEXML_Char *systemId )
    {
    }

    virtual void unparsedEntityDecl( const ACEXML_Char *name, const ACEXML_Char *publicId, const ACEXML_Char *systemId, const ACEXML_Char *notationName )
    {
        
    }

    virtual ACEXML_InputSource * resolveEntity( const ACEXML_Char *publicId, const ACEXML_Char *systemId )
    {
        return 0;
    }

    virtual void error( ACEXML_SAXParseException &exception )
    {
    }

    virtual void fatalError( ACEXML_SAXParseException &exception )
    {
    }

    virtual void warning( ACEXML_SAXParseException &exception )
    {
    }

private:
    //xml文件路径
    string filepath_;
    ACEXML_Locator* locator_;
    ROOT root_;
    vector<ROOT_FILE*> files_;
    enum FLAG
    {
        FLAG_NULL,
        FLAG_ROOT,
        FLAG_FILE,
    };
    int flag_;
};

xml_parser完整代码展示

#include "ACEXML/common/FileCharStream.h"
#include "ACEXML/parser/parser/Parser.h"

//对xml文件进行解析的类,将解析后的数据保存的格式依赖于HANDLER类
//HANDLER 必须继承自ACEXML_DefaultHandler类,并且提供"string path();"这样的方法
//注意:此对象不提供多进程或多线程按序访问的功能
template< typename HANDLER>
class xml_parser
{
public:
    static bool parse(HANDLER& handler)
    {
        ACEXML_FileCharStream* fstm = new(std::nothrow)ACEXML_FileCharStream();
        if(!fstm)
        {
            return false;
        }
        string path = handler.path();
        if(path.empty())
        {
            return false;
        }
        fstm->open(path.c_str());
        //ACEXML_InputSource类的析构方法中会通过“delete fstm”来释放内存
        ACEXML_InputSource input(fstm);
        ACEXML_Parser parser;
        parser.setContentHandler(&handler);
        parser.setDTDHandler(&handler);
        parser.setEntityResolver(&handler);
        parser.setErrorHandler(&handler);
        try
        {
            parser.parse(&input);
        }
        catch(const ACEXML_Exception* ex)
        {
            ex->print();
            return false;
        }
        catch(std::bad_alloc& ex)
        {
            return false;
        }
        return true;
    }
};

调用代码展示

#include "xml_handler.h"
#include "xml_parser.h"

int main(int argc, char* argv[])
{
    xml_handler handler("D:\\test.xml");
    xml_parser<xml_handler>::parse(handler);
    cout << "root version:" << handler.root().version << ", count:" << handler.root().count << endl;
    cout << "---------------------" << endl;
    for(size_t i=0; i<handler.count(); ++i)
    {
            cout << "file id:" << handler[i]->id << ", path:" << handler[i]->path << endl;
    }
    return 0;
};

源代码下载

ACEXMLParserDemo

系列链接

ACEXML解析XML文件——我是如何学习并在短时间内掌握一个库的使用方法的

ACEXML解析XML文件——简单示例程序

posted on 2014-01-04 14:33  缘生梦  阅读(1669)  评论(0编辑  收藏  举报