最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

Xerces C++解析XML文档

来源:动视网 责编:小OO 时间:2025-10-01 21:02:26
文档

Xerces C++解析XML文档

XercesC++解析XML文档Xerces-C++是什么?     Xerces-C++的前身是IBM的XML4C项目。XML4C和XML4J是两个并列的项目,而XML4J是Xerces-J——Java实现——的前身。IBM将这两个项目的源代码让与Apache软件基金会(ApacheSoftwareFoundation),他们将其分别改名为Xerces-C++和Xerces-J。这两个项目是ApacheXML组的核心项目(如果看到的是“Xerces-C”而不是“Xerces-C++”,也是同
推荐度:
导读XercesC++解析XML文档Xerces-C++是什么?     Xerces-C++的前身是IBM的XML4C项目。XML4C和XML4J是两个并列的项目,而XML4J是Xerces-J——Java实现——的前身。IBM将这两个项目的源代码让与Apache软件基金会(ApacheSoftwareFoundation),他们将其分别改名为Xerces-C++和Xerces-J。这两个项目是ApacheXML组的核心项目(如果看到的是“Xerces-C”而不是“Xerces-C++”,也是同
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

      

       <国家调查>

      

      

        

           china     111-> 江苏

           china     112-> 天津

           china     113-> 北京

           china     114-> 上海

           china     115-> 广州

         

       

           Asia     12-> 韩国

           Asia     13-> 日本

           Asia     14-> 越南

           Asia     15-> 柬埔寨

           Asia     16-> 老挝

       

       

           America   21-> 巴西

           America   22-> 阿根廷

           America   23-> 智利

           America   24-> 墨西哥

           America   25-> 巴拉圭

           America   26-> 美国

           America   27-> 加拿大

      

      

          Europe   31-> 英国

          Europe   32-> 意大利

          Europe   33-> 法国

          Europe   34-> 德国

          Europe   35-> 西班牙

          Europe   36-> 匈牙利

      

       THE END

      

       定义好格式后,我们来看看程序是如何实现对其解析的,程序如下:

CODE:

[Copy to clipboard]

//CXML.h

#ifndef XML_PARSER_HPP

#define XML_PARSER_HPP

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#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(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 <             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 <      }

  

   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   toFill[i]=0;

}

[/i]string XMLStringTranslate::translate(const XMLCh* const value)    //实现从 XMLCh* 到 string类型的转换

{

*fFormatter<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编码的中文正常的解析打印出来了。

文档

Xerces C++解析XML文档

XercesC++解析XML文档Xerces-C++是什么?     Xerces-C++的前身是IBM的XML4C项目。XML4C和XML4J是两个并列的项目,而XML4J是Xerces-J——Java实现——的前身。IBM将这两个项目的源代码让与Apache软件基金会(ApacheSoftwareFoundation),他们将其分别改名为Xerces-C++和Xerces-J。这两个项目是ApacheXML组的核心项目(如果看到的是“Xerces-C”而不是“Xerces-C++”,也是同
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top