ACEXML解析XML文件——简单示例程序
掌握了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;
};
源代码下载
系列链接
ACEXML解析XML文件——我是如何学习并在短时间内掌握一个库的使用方法的
ACEXML解析XML文件——简单示例程序的更多相关文章
- ACEXML解析XML文件——我是如何学习并在短时间内掌握一个库的使用方法的
最近做的C++项目中需要使用xml文件保存一些信息,程序启动时会读取这些信息.最终经过主程的评测,决定使用ACEXML库来读取解析XML文件. 好吧,至于为什么选择ACEXML库,我就不说了.既然选择 ...
- Java是如何解析xml文件的(DOM)
Java解析xml文件 在Java程序中读取xml文件的过程也称为"解析xml文件": 解析的目的: 获取 节点名和节点值 获取 属性名.属性值. 四中解析方式: DOM SAX ...
- Android程序解析XML文件的方法及使用PULL解析XML案例
一.一般解析XML文件的方法有SAX和DOM.PULL (1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信 ...
- 解析XML文件示例
项目中要解析Xml文件,于是在工程里找了下前人写例子. 1,SAX(基于事件,效率高,使用声明加载什么). public class MVCConfig { private static MVCCon ...
- Android中pull解析XML文件的简单使用
首先,android中解析XML文件有三种方式,dom,sax,pull 这里先讲pull,稍候会说SAX和DOM pull是一种事件驱动的xml解析方式,不需要解析整个文档,返回的值是数值型,是推荐 ...
- JQuery -- Jquery 中的Ajax, Jquery解析xml文件
1. JQuery 对 Ajax 操作进行了封装,在 jQuery 中最底层的方法时 $.ajax(), 第二层是 load(), $.get() 和 $.post(),第三层是$.getScript ...
- DOM4J方式解析XML文件
dom4j介绍 dom4j的项目地址:http://sourceforge.net/projects/dom4j/?source=directory dom4j是一个简单的开源库,用于处理XML. X ...
- 深入浅出如何解析xml文件---下篇
在上篇博文中,小编主要介绍xml的两种解析方式,分别是dom4j和dom,今天这篇博文,小编主要来简单介绍一下xml的其她两种解析方式sax和jdom. sax解析xml文件 sax,全称是Simp ...
- 深入浅出如何解析xml文件---上篇
xml小伙伴们并不陌生,xml是可扩展标记语言,标准通用标记语言语言的子集,是一种用来标记电子文件使其具有结构性的标记语言.我们知道xml可以用dom与sax等方法进行解析,但是xml为什么要解析呢? ...
随机推荐
- 122. Best Time to Buy and Sell Stock(二) leetcode解题笔记
122. Best Time to Buy and Sell Stock II Say you have an array for which the ith element is the price ...
- cv_prj2
Computer Vision Project 2 – Harris Corner Detector 姓名: 王兴路 学号: 3140102282 指导老师: 宋明黎 2016-12-16 19:30 ...
- 【extjs】:获取列名,时间转换
1.日期字符戳转时间 renderer : function(value, arg2) { if (value != null && value != ' ...
- jquery制作弹出层带遮罩效果,点击阴影部分层消失
jquery制作弹出层带遮罩效果,点击阴影部分层消失. 整体还是比较简单的. HTML代码很简单 <a href="#" class="big-link" ...
- linux系统编程之lseek帮助文档
通过man 2 lseek可以查看linux中的系统函数lseek函数的帮助文档,为了更好的学习,我把这些重要内容翻译过来 NAME lseek - reposition read/write fil ...
- XML解析、使用TreeView呈现效果
首先用到TXMLDocument控件: Memo来显示XML文件, TreeView来呈现元素: 源代码: Procedure TForm2.Button1Click(Sender: TObject) ...
- jackson json转list
今天项目中用到了jackson,经理说效率高一些,所以就开始用起来,一开始json转对象,对象转json还是很简单的,但也还是有一些问题,后来加了一点配置属性就没有报错了 ObjectMapper m ...
- [转载]Firebird与MySQL:一个使用者的体会
老板要我开发一个LINUX平台上的数据库项目,要求一定要用开源免费数据库.我知道这个数据库必须能够上网操作,同时作为公司的核心骨干数据库,除了必须是稳定的存储数据库外还必须有很强的数据和数据库控管功能 ...
- eclipse js 引用跳转
引用 http://stackoverflow.com/questions/24505993/the-resource-is-not-on-the-build-path-of-a-javascript ...
- Services (服务)
*/ .hljs { display: block; padding: 0.5em; background: #F0F0F0; } .hljs, .hljs-subst, .hljs-tag .hlj ...