zoukankan      html  css  js  c++  java
  • ACEXML解析XML文件——简单示例程序

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

    定义基本结构

    xml文件格式如下

    <?xml version="1.0"?>
    <root version="9" count="3" >
        <file id="1">D:	est1.txt</file>
        <file id="2">D:	est2.txt</file>
        <file id="3">D:	est3.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 << "	<" << 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 << "	<" << 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 << "	<" << 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文件——简单示例程序

  • 相关阅读:
    java位运算
    java笔试题(面试题)系列之一
    Java数据类型转换总结
    ++a和a++
    Java IO
    Java 并发
    Java位运算及补码存储
    Redis 5.0.0安装部署(伪集群版)
    Redis 安装(单机版)
    Dubbo源码分析系列之【服务暴露】
  • 原文地址:https://www.cnblogs.com/hbccdf/p/3504835.html
Copyright © 2011-2022 走看看