利用Xerces C++解析XML文档
<br />首页 资讯 移动 云计算 空间 学生 论坛 博客 下载 网摘 程序员 外包 书店 CTO俱乐部 TUP 培训充电 D9区 <br />liuchang5的专栏<br />条新通知 登录 注册 欢迎 murongfeiyue! 退出 我的博客 配置 写文章 文章管理 博客首页 全站 当前博客 空间 博客 好友 相册 留言 用户操作 <br />[留言] [发消息] [加为好友]
首页 资讯 移动 云计算 空间 学生 论坛 博客 下载 网摘 程序员 外包 书店 CTO俱乐部 TUP 培训充电 D9区
liuchang5的专栏
条新通知 登录 注册 欢迎 murongfeiyue! 退出 我的博客 配置 写文章 文章管理 博客首页 全站 当前博客 空间 博客 好友 相册 留言 用户操作
[留言] [发消息] [加为好友]
刘畅ID:liuchang5
共8518次访问,排名17996,好友2人,关注者4人。
刘畅的文章
原创 19 篇
翻译 0 篇
转载 11 篇
评论 3 篇
订阅我的博客
[编辑]liuchang5的公告
[编辑]文章分类
Ajax
C/C++
Flex
lua
操作系统
图形图像
网站开发
文献检索
存档
2010年07月(8)
2009年03月(1)
2009年01月(9)
2008年12月(10)
2008年11月(2)
公告: CSDN招聘.NET开发工程师 [意见反馈][官方博客] 浅谈利用Xerces C++解析XML文档 收藏
前一阵子学习Xerces-C++用于解析指定格式XML文档。在这里,把自己的学习经历和大家分享一下,在这里仅仅讲一些入门的知识,希望对大家有所帮助。
Xerces-C++是什么?
Xerces-C++ 的前身是 IBM 的 XML4C 项目。XML4C 和 XML4J 是两个并列的项目,而 XML4J 是 Xerces-J——Java 实现——的前身。IBM 将这两个项目的源代码让与 Apache 软件基金会(Apache Software Foundation),他们将其分别改名为 Xerces-C++ 和 Xerces-J。这两个项目是 Apache XML 组的核心项目(如果看到的是“Xerces-C”而不是“Xerces-C++”,也是同一个东西,因为这个项目一开始就是用 C(译者注:原文为C++)语言编写的)。
Xerces-C++: 功能介绍
Xerces-C++是一个非常健壮的 XML 解析器,其提供的两种解析XML文档的方法,DOM和SAX (我是采用DOM方法)。
SAX是一个面向事件的编程API.一个解析引擎消耗XML序列数据,并在发现进来的XML数据的结构时回调应用程序,这些回调称为事件句柄.
与SAX不同,它允许对XML文档进行编辑并保存为一个文件或者流,还允许以编程的方式构建一个XML文档.DOM提供了一个内存中的模型,你可以遍历文档树,删除节点或者嫁接新节点.与解析的SAX事件不同,DOM事件反映出用户与文档的互动以及使用文档的改变.
总的来说,SAX是按行遍历XML文档的,而DOM是先把XML文档生成树,然后遍历DOM树,来解析每个节点.
Xerces-C++:学习的过程
1、平台选择:
在学习Xerces-C++之前你必须选择一种应用平台,可以是windows、linux、cygwin,以及solaris等系统平台。在这里,我选用的是Redhat Enterprise Linux AS3,选用的Xerces-C++ 是xerces-c-src_2_7_0.tar.gz,可以从官方网站:http://www.apache.org/ 直接下载。
2、编译源码
由于我下载下来的是源码,所以需要对其进行编译,否则我们无法加载库文件。
首先进入你的工作目录:cd /home/olcom/laubo(这是我当前工作目录)
然后解压你的源码包: tar zxvf xerces-c-src_2_7_0.tar.gz
设置包含源代码的环境变量:
export XERCESCROOT=/home/olcom/laubo/xerces-c-src_2_7_0
进入目录:cd xerces-c-src_2_7_0/src/xercesc
运行脚本生成makefile文件:
./runConfigure -plinux -cgcc -xg++ -C--prefix=/opt/ApacheXML
选项: -p 为操作系统平台
-c C 编译器
-x C++编译器
-c 库的配置路径
编译源码:make
make install
(编译可能要花费你好一会儿,在我的机器上花费大约7分钟的时间,所以要耐心等候)
3、学习类库
因为类库很大,所以刚开始,我并没有选择去分析与阅读类库,我是先在网上了一个比较完整的例子,然后对其进行编译和调试,然后从例子下手去分析类库所提供的接口。这里,我把自己的程序简化了一下,希望可以作为大家学习的例子。
首先,我们需要定义一种 XML文档的样式。在这里,我们简单的定义一种样式(含有中文),如下:
//sample.xml
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<国家调查>
<Node1>
<subNode>
<subNode1>
<subNode11>china 111-> 江苏 </subNode11>
<subNode11>china 112-> 天津 </subNode11>
<subNode11>china 113-> 北京 </subNode11>
<subNode11>china 114-> 上海 </subNode11>
<subNode11>china 115-> 广州 </subNode11>
</subNode1>
</subNode>
<subNode1>Asia 12-> 韩国 </subNode1>
<subNode2>Asia 13-> 日本 </subNode2>
<subNode3>Asia 14-> 越南 </subNode3>
<subNode4>Asia 15-> 柬埔寨 </subNode4>
<subNode5>Asia 16-> 老挝 </subNode5>
</Node1>
<Node2>
<subNode>America 21-> 巴西 </subNode>
<subNode>America 22-> 阿根廷 </subNode>
<subNode>America 23-> 智利 </subNode>
<subNode>America 24-> 墨西哥 </subNode>
<subNode>America 25-> 巴拉圭 </subNode>
<subNode>America 26-> 美国 </subNode>
<subNode>America 27-> 加拿大 </subNode>
</Node2>
<Node3>
<subNode>Europe 31-> 英国</subNode>
<subNode>Europe 32-> 意大利 </subNode>
<subNode>Europe 33-> 法国</subNode>
<subNode>Europe 34-> 德国 </subNode>
<subNode>Europe 35-> 西班牙</subNode>
<subNode>Europe 36-> 匈牙利 </subNode>
</Node3>
<Node5>THE END </Node5>
</国家调查>
定义好格式后,我们来看看程序是如何实现对其解析的,程序如下:
CODE:[Copy to clipboard]
//CXML.h
#ifndef XML_PARSER_HPP
#define XML_PARSER_HPP
#include <xercesc/util/TransService.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMDocumentType.hpp>
#include <xercesc/dom/DOMElement.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/dom/DOMImplementationLS.hpp>
#include <xercesc/dom/DOMNodeIterator.hpp>
#include <xercesc/dom/DOMNodeList.hpp>
#include <xercesc/dom/DOMText.hpp>
#include <xercesc/dom/DOMAttr.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/framework/XMLFormatter.hpp>
#include <xercesc/util/XMLString.hpp>
#include <stdlib.h>
#include <string>
#include <vector>
#include <stdexcept>
using namespace std;
using namespace xercesc;
class XMLStringTranslate;
class CXML
{
public:
CXML();
~CXML();
XMLTransService::Codes tranServiceCode;
void xmlParser(string&) throw(std::runtime_error);
private:
XMLStringTranslate *XMLTan;
xercesc::XercesDOMParser *m_DOMXmlParser; //定义解析对象
};
class XMLStringTranslate : public XMLFormatTarget
{
public:
XMLStringTranslate(const char * const encoding);
bool TranslatorUTF8ToChinese(string &strTranslatorMsg);
bool UTF8_2_GB2312(char *in, int inLen, char *out, int outLen);
string translate(const XMLCh* const value);
const XMLCh * const translate(const char * const value);
virtual ~XMLStringTranslate();
protected:
XMLFormatter * fFormatter;
XMLCh * fEncodingUsed;
XMLCh * toFill;
char * m_value;
protected:
enum Constants
{
kTmpBufSize = 16 * 1024,
kCharBufSize = 16 * 1024
};
void clearbuffer();
virtual void writeChars(const XMLByte* const toWrite
, const unsigned int count
, XMLFormatter* const formatter);
};
#endif
//CXML.cpp
#include <string>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <list>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <iconv.h>
#include "CXML.h"
bool XMLStringTranslate::UTF8_2_GB2312(char *in, int inLen, char *out, int outLen) //码型转换
{
iconv_t cd = iconv_open( "gbk", "UTF-8" );
// check cd
if( (int)cd == -1 )
{
cout << "iconv is ERROR" << endl;
return false;
}
char *pin = in, *pout = out;
int inLen_ = inLen + 1;
int outLen_ = outLen;
iconv( cd, &pin, (size_t*)&inLen_, &pout, (size_t*)&outLen_ );
iconv_close(cd);
return true;
}
bool XMLStringTranslate::TranslatorUTF8ToChinese(string &strTranslatorMsg)
{
char* pstrSource = const_cast<char*>(strTranslatorMsg.c_str());
char pstrDestination[strTranslatorMsg.length()*2+1]; //如此处编译出错,可改为char *pstrDestination = new char[strTranslatorMsg.length()*2+1], 但要记住释放
memset(pstrDestination, '/0', strTranslatorMsg.length()*2+1);
if(!UTF8_2_GB2312(pstrSource, strTranslatorMsg.length(), pstrDestination, strTranslatorMsg.length()))
return false;
strTranslatorMsg = pstrDestination;
return true;
}
CXML::CXML()
{
try
{
// Initialize Xerces-C++ library
XMLPlatformUtils::Initialize();
}
catch(xercesc::XMLException & excp)
{
char* msg = XMLString::transcode(excp.getMessage());
printf("XML toolkit initialization error: %s/n", msg);
XMLString::release(&msg);
}
XMLTan = new XMLStringTranslate("utf-8");
//创建 XercesDOMParser 对象,用于解析文档
m_DOMXmlParser = new XercesDOMParser;
}
CXML::~CXML()
{
try
{
delete XMLTan;
XMLPlatformUtils::Terminate();
}
catch(XMLException& excp)
{
char* msg = XMLString::transcode(excp.getMessage());
printf("XML toolkit terminate error: %s/n", msg);
XMLString::release(&msg);
}
}
void CXML::xmlParser(string & xmlFile) throw( std::runtime_error )
{
//获取文件信息状态
struct stat fileStatus;
int iretStat = stat(xmlFile.c_str(), &fileStatus);
if( iretStat == ENOENT )
throw ( std::runtime_error("file_name does not exist, or path is an empty string.") );
else if( iretStat == ENOTDIR )
throw ( std::runtime_error("A component of the path is not a directory."));
else if( iretStat == ELOOP )
throw ( std::runtime_error("Too many symbolic links encountered while traversing the path."));
else if( iretStat == EACCES )
throw ( std::runtime_error("ermission denied."));
else if( iretStat == ENAMETOOLONG )
throw ( std::runtime_error("File can not be read/n"));
//配置DOMParser
m_DOMXmlParser->setValidationScheme( XercesDOMParser::Val_Auto );
m_DOMXmlParser->setDoNamespaces( false );
m_DOMXmlParser->setDoSchema( false );
m_DOMXmlParser->setLoadExternalDTD( false );
try
{
//调用 Xerces C++ 类库提供的解析接口
m_DOMXmlParser->parse(xmlFile.c_str()) ;
//获得DOM树
DOMDocument* xmlDoc = m_DOMXmlParser->getDocument();
DOMElement *pRoot = xmlDoc->getDocumentElement();
if (!pRoot )
{
throw(std::runtime_error( "empty XML document" ));
}
// create a walker to visit all text nodes.
/**********************************************
DOMTreeWalker *walker =
xmlDoc->createTreeWalker(pRoot, DOMNodeFilter::SHOW_TEXT, NULL, true);
// use the tree walker to print out the text nodes.
std::cout<< "TreeWalker:/n";
for (DOMNode *current = walker->nextNode(); current != 0; current = walker->nextNode() )
{
char *strValue = XMLString::transcode( current->getNodeValue() );
std::cout <<strValue;
XMLString::release(&strValue);
}
std::cout << std::endl;
*************************************************/
// create an iterator to visit all text nodes.
DOMNodeIterator* iterator = xmlDoc->createNodeIterator(pRoot,
DOMNodeFilter::SHOW_TEXT, NULL, true);
// use the tree walker to print out the text nodes.
std::cout<< "iterator:/n";
for ( DOMNode * current = iterator->nextNode();
current != 0; current = iterator->nextNode() )
{
string strValue = XMLTan->translate(current->getNodeValue() );
XMLTan->TranslatorUTF8ToChinese(strValue);
std::cout <<strValue<<endl;
}
std::cout<< std::endl;
}
catch( xercesc::XMLException& excp )
{
char* msg = xercesc::XMLString::transcode( excp.getMessage() );
ostringstream errBuf;
errBuf << "Error parsing file: " << msg << flush;
XMLString::release( &msg );
}
}
XMLStringTranslate::XMLStringTranslate(const char * const encoding):fFormatter(0),
m_value(0),fEncodingUsed(0),toFill(0)
{
XMLFormatTarget * myFormTarget = this;
fEncodingUsed=XMLString::transcode(encoding);
fFormatter = new XMLFormatter(fEncodingUsed
,myFormTarget
,XMLFormatter::NoEscapes
,XMLFormatter::UnRep_CharRef);
toFill=new XMLCh[kTmpBufSize];
clearbuffer();
}
XMLStringTranslate::~XMLStringTranslate()
{
if(fFormatter)
delete fFormatter;
if(fEncodingUsed)
delete [] fEncodingUsed;
if(m_value)
free(m_value);
if(toFill)
free(toFill);
fFormatter=0;
fEncodingUsed=0;
m_value=0;
toFill=0;
}
void XMLStringTranslate::writeChars(const XMLByte* const toWrite
, const unsigned int count
, XMLFormatter* const formatter)
{
if(m_value)
free(m_value);
m_value=0;
m_value=new char[count+1];
memset(m_value,0,count+1);
memcpy(m_value,(char *)toWrite,count+1);
}
void XMLStringTranslate::clearbuffer()
{
if(!toFill)
return;
for(int i=0;i<kTmpBufSize;i++)
toFill[i]=0;
}
[/i]string XMLStringTranslate::translate(const XMLCh* const value) //实现从 XMLCh* 到 string类型的转换
{
*fFormatter<<value;
string strValue=string(m_value);
return strValue;
}
const XMLCh * const XMLStringTranslate::translate(const char * const value)
{
clearbuffer();
const unsigned int srcCount=XMLString::stringLen(value);
unsigned char fCharSizeBuf[kCharBufSize];
XMLTranscoder * pTranscoder=(XMLTranscoder *)fFormatter->getTranscoder();
unsigned int bytesEaten;
unsigned int size=pTranscoder->transcodeFrom(
(XMLByte *)value,
srcCount,
toFill,
kTmpBufSize,
bytesEaten,
fCharSizeBuf
);
toFill[size]=0;
string t1=string(value);
string t2=translate(toFill);
assert(t1==t2);
return toFill;
}
#ifdef MAIN_TEST
int main()
{
string xmlFile = "sample.xml";
CXML cxml;
cxml.xmlParser(xmlFile);
return 0;
}
#endif
//Makefile
#tHIS IS MAKEFILE FOR XERCES-C++ APPLIACTION
MAIN = xml
CC = g++
CFLAGS = -c -g -Wall
$(MAIN):CXML.o
[TAB]$(CC) CXML.o -o xml -L/opt/ApacheXML/lib -lxerces-c
CXML.o:CXML.cpp
[TAB]$(CC) $(CFLAGS) -pedantic -I/opt/ApacheXML/include CXML.cpp -DMAIN_TEST
.PHONY:clean
clean:
[TAB]rm CXML.o $(MAIN)
下面简要分析一下源程序:
首先,要想利用Xerces C++类库来解析XML文档,必须要对类库进行初始化,所以在类XML的构造函数中,我们对类库进行了初始化:XMLPlatformUtils::Initialize();
接下来,我们定义的解析对象,并在构造函数中对其进行了初始化操作,然后,在xmlParser函数中我们调用类库的解析函数接口,传人xml文件名(m_DOMXmlParser->parse(xmlFile.c_str()) ;)。因为在这里我们选用的是DOM方法,所以接下来我们需要创建DOM树:DOMDocument* xmlDoc = m_DOMXmlParser->getDocument();,并获取DOM树的根节点 DOMElement *pRoot = xmlDoc->getDocumentElement()。
再接下来是什么呢?根据上面所说的,我们需要遍历这棵DOM树,因此我们需要一种遍历方法,在程序中我给出了两种遍历的方法,一种是创建遍历树DOMTreeWalker *walker = xmlDoc->createTreeWalker(pRoot, DOMNodeFilter::SHOW_TEXT, NULL, true),还有一种是通过迭代器来遍历整棵DOM树 DOMNodeIterator* iterator = xmlDoc->createNodeIterator(pRoot, DOMNodeFilter::SHOW_TEXT, NULL, true)。两种方法都可以达到同样的效果。程序中注释掉的代码是创建遍历树方法。
遍历完,并打印出节点值以后,我们需要终止对类库的调用,所以在析构函数中:XMLPlatformUtils::Terminate()。
解析简单xml文档的基本步骤就是如此简单,至于复杂的XML文档,解析的步骤,尤其是创建DOM树的方法有点不同,在这里便不作介绍。接下来,来讲一下困扰我多天的中文解析问题。我们知道,Xerces C++默认只支持节点名中文,至于节点值,属性值则不支持,即使 解析出来的也是乱码,所以需要自己解决。在这里,我们选用UTF-8编码格式的XML文档。先来看一下乱码的原因,由于XML解析器解析的字符串都是XMLCh*(typedef unsigned int XMLCh)格式的,一个字符占用一个字节,而汉字字符确要占用两个字节。故若不做适当的转换,汉字的输出结果就变成乱码了。在 http://www.vckbase.com/document/viewdoc/?id=738 提供了一种解决的方法,但是那个解决方案只有在locale环境为UTF-8的情况下你才可以看见正常的中文输出,在locale为GB18030等环境下,你的中文是乱码。但是在一种环境下可以正常显示,说明已经可以正常解析出来了,只是在不同环境的机器上需要进行码型转换,因此,我在他提供的类中又添加了两种方法,来进行码型转换:
bool TranslatorUTF8ToChinese(string &strTranslatorMsg); //实现从UTF-8到GBK、GB2312等码型的转换
bool UTF8_2_GB2312(char *in, int inLen, char *out, int outLen);
这样,你就可以在把UTF-8编码的中文正常的解析打印出来了。
XML文档的解析的样式很多,所以编出来的解析程序不可能达到通用的效果,不同的XML文档,解析的要求和方法都各有所异(如同时打印出你的节点名和节点值,上述的方法就不可行),所以还需要改动你的程序,所以如果你对解析XML有兴趣的话,可以深入的理解一下Xerces C++类库。
发表于 @ 2010年07月30日 13:06:00 | 评论( 0 ) | 编辑| 举报| 收藏
旧一篇:Xerces-C++的安装配置方法 | 新一篇:使用MsXML存取XML
查看最新精华文章 请访问博客首页相关文章 发表评论 表 情: 评论内容: 用 户 名: 登录 注册 匿名评论 murongfeiyue验 证 码: 重新获得验证码 热门招聘职位【B2C网站】高薪诚聘Java /.NET开发工程师!【浩辰CAD】国产CAD第一品牌 高薪诚聘 高级VC++开发职位【麒麟游戏】倾情招聘募游戏研发人员,共建麒麟家园!【神灯网络】年薪20万!诚聘DELPHI高级项目经理!【并擎软件】微软高级技术专家诚邀开发人员共同创业【人民搜索】多个技术研发类职位,等你来挑战!【百度】诚聘 Web研发/工程师 一个舞台,让你的想法去成为现实!!!【上海我友】福利购房计划+高薪+期权,邀您共创互联网的奇迹!【NHN China】诚聘QA工程师/软件开发工程师, 急聘!高薪诚聘!【Synopsys】全球知名EDA软件设计公司,诚聘 C/C++/IC Engineer【麻省理工】《科技创业》诚聘网络编辑、PHP开发工程师!【艾瑞威尔】高薪诚募Apple游戏开发工程师 一流环境+一流待遇 【B2C网站】高薪诚聘Java /.NET开发工程师!【浩辰CAD】国产CAD第一品牌 高薪诚聘 高级VC++开发职位【麒麟游戏】倾情招聘募游戏研发人员,共建麒麟家园!【神灯网络】年薪20万!诚聘DELPHI高级项目经理!【并擎软件】微软高级技术专家诚邀开发人员共同创业【人民搜索】多个技术研发类职位,等你来挑战!【百度】诚聘 Web研发/工程师 一个舞台,让你的想法去成为现实!!!【上海我友】福利购房计划+高薪+期权,邀您共创互联网的奇迹!【NHN China】诚聘QA工程师/软件开发工程师, 急聘!高薪诚聘!【Synopsys】全球知名EDA软件设计公司,诚聘 C/C++/IC Engineer【麻省理工】《科技创业》诚聘网络编辑、PHP开发工程师!【艾瑞威尔】高薪诚募Apple游戏开发工程师 一流环境+一流待遇 公司简介|招贤纳士|广告服务|银行汇款帐号|联系方式|版权声明|法律顾问|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
江苏乐知网络技术有限公司 提供商务支持
Email:webmaster@csdn.net
Copyright © 1999-2010, CSDN.NET, All Rights Reserved
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/liuchang5/archive/2010/07/30/5776246.aspx
更多推荐
所有评论(0)