掌握了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文件——简单示例程序

ACEXML解析XML文件——简单示例程序的更多相关文章

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

    最近做的C++项目中需要使用xml文件保存一些信息,程序启动时会读取这些信息.最终经过主程的评测,决定使用ACEXML库来读取解析XML文件. 好吧,至于为什么选择ACEXML库,我就不说了.既然选择 ...

  2. Java是如何解析xml文件的(DOM)

    Java解析xml文件 在Java程序中读取xml文件的过程也称为"解析xml文件": 解析的目的: 获取 节点名和节点值 获取 属性名.属性值. 四中解析方式: DOM SAX ...

  3. Android程序解析XML文件的方法及使用PULL解析XML案例

    一.一般解析XML文件的方法有SAX和DOM.PULL (1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信 ...

  4. 解析XML文件示例

    项目中要解析Xml文件,于是在工程里找了下前人写例子. 1,SAX(基于事件,效率高,使用声明加载什么). public class MVCConfig { private static MVCCon ...

  5. Android中pull解析XML文件的简单使用

    首先,android中解析XML文件有三种方式,dom,sax,pull 这里先讲pull,稍候会说SAX和DOM pull是一种事件驱动的xml解析方式,不需要解析整个文档,返回的值是数值型,是推荐 ...

  6. JQuery -- Jquery 中的Ajax, Jquery解析xml文件

    1. JQuery 对 Ajax 操作进行了封装,在 jQuery 中最底层的方法时 $.ajax(), 第二层是 load(), $.get() 和 $.post(),第三层是$.getScript ...

  7. DOM4J方式解析XML文件

    dom4j介绍 dom4j的项目地址:http://sourceforge.net/projects/dom4j/?source=directory dom4j是一个简单的开源库,用于处理XML. X ...

  8. 深入浅出如何解析xml文件---下篇

    在上篇博文中,小编主要介绍xml的两种解析方式,分别是dom4j和dom,今天这篇博文,小编主要来简单介绍一下xml的其她两种解析方式sax和jdom.  sax解析xml文件 sax,全称是Simp ...

  9. 深入浅出如何解析xml文件---上篇

    xml小伙伴们并不陌生,xml是可扩展标记语言,标准通用标记语言语言的子集,是一种用来标记电子文件使其具有结构性的标记语言.我们知道xml可以用dom与sax等方法进行解析,但是xml为什么要解析呢? ...

随机推荐

  1. windows获取硬盘使用率等信息

    #coding=utf8 import psutil cpu = {'user' : 0, 'system' : 0, 'idle' : 0, 'percent' : 0} mem = {'total ...

  2. HttpWebRequest类

    HttpWebRequest类与HttpRequest类的区别. HttpRequest类的对象用于服务器端,获取客户端传来的请求的信息,包括HTTP报文传送过来的所有信息.而HttpWebReque ...

  3. map阶段动态获取CombineTextInputFormat各输入文件路径

    老mr程序中map中conf的map.input.file参数只能获取获取CombineTextInputFormat的第一个输入文件,而新版mr程序则连第一个输入文件也无法获取,这是因为create ...

  4. ORACLE 自动增长通过封装函数,方便调用

    好的编程习惯,是一个很有必要的过程.好的编程习惯,可以因人而异,但是简单地.基本地代码级别的就那些:写注释.合理的缩进.换行.变量命名等. 对我们程序员来说,大部分时间都对着电脑,在对着电脑的大部分时 ...

  5. js基础知识点总结

    如何在一个网站或者一个页面,去书写你的js代码:1.js的分层(功能):jquery(tool) 组件(ui) 应用(app),mvc(backboneJs)2.js的规划():避免全局变量和方法(命 ...

  6. iOS基础之网络请求相关

    1.AFNetwork二次封装方法一: #import <Foundation/Foundation.h> @interface BeeNetworkManager : NSObject ...

  7. BeanUtils: 威力和代价(转载)

    转自:http://blog.sina.com.cn/s/blog_ab3fbf1b0101jbxz.html Apache Jakarta Commons项目非常有用.我曾在许多不同的项目上或直接或 ...

  8. JavaScript-事件周期-点击替换颜色

    事件周期 DOM:3个阶段 1.捕获:从最外层元素,向内层元素,逐个记录绑定的事件处理函数.默认,暂不触发任何事件 2.目标触发:优先触发目标元素绑定的事件处理函数 目标元素:实际点击的元素 3.冒泡 ...

  9. Opacity多浏览器透明度兼容处理

    用来设定元素透明度的 Opacity 是CSS 3里的一个属性.当然现在还只有少部分浏览器支持. 不过各个浏览器都有自己的私有属性来支持,其中包括老版本的Mozilla和Safari: IE: fil ...

  10. Windows下Spark单机环境配置

    1. 环境配置 a)  java环境配置: JDK版本为1.7,64位: 环境变量配置如下: JAVA_HOME为JDK安装路径,例如D:\software\workSoftware\JAVA 在pa ...