Xerces C++ DOM解析XML文档

原创 2012年03月30日 08:51:44

前一阵子学习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数据的结构时回调应用程序,这些回调称为事件句柄.

    DOM与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文档的样式。在这里,我们简单的定义一种样式(含有中文),如下:

<?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>
            </国家调查>

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

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

xml4c   ------http://www.alphaworks.ibm.com/tech/xml4c

  IBM的XML   Parser,用c++语言写就,功能超级强大。号称支持多达100种字符编码,能够支持中文,

适合于大规模的xml应用。若只是很小范围的应用,则非最佳选择,毕竟,你需要“背负”约12M左右的

dll的沉重负担。

 Xerces   c++   -------http://xml.apache.org/xerces-c

  Apache的XML项目,同样是c++   实现,来源于IBM的xml4c,因此编程接口也是和xml4c一致的。但是

目前只支持少数的字符编码,如ASCII,UTF-8,UTF-16等,不能处理包含中文字符的XML文档。

     Xerces-C++   是一个非常健壮的XML解析器,它提供了验证,以及SAX和DOM   API。XML验证在文档类型定

义(Document   Type  Definition,DTD)方面有很好的支持,并且在2001年12月增加了支持W3C   XML   Schema 

的基本完整的开放标准。

XMLBooster -------http://www.xmlbooster.com/

       这个库通过产生特制的parser的办法极大的提高了XML解析的速度,并且能够产生相应的GUI程序

来修改这个parser。在DOM和SAX两大主流XML解析办法之外提供了另外一个可行的解决方案。


使用Xerces DOM 处理XML文件

最近需要处理XML文件,学习了一下Xerces类库。同其他的XML解析库相比,这个类库比较庞大,功能也相对比较完善。Xerces C++是其中的C++类库,相对的,还有一个JAVA类库。使用Xerce...

XML解析简介及Xerces-C++简单使用举例

XML解析简介及Xerces-C++简单使用举例!

xerces-c用DOM方式操作xml

xerces-c是一个可以校验XML合法性的XML解析器,它的语言是C++,它的官方主页:http://xml.apache.org/xerces-c。它支持下面这些标准:XML 1.0 ,XML 1...
  • xuzhina
  • xuzhina
  • 2015年07月09日 11:33
  • 2588

基于Dom的C++解析html

采集网页内容时,经常要读取html标签,解析后获取其中的文字信息,Python有BeautifulSoup,javascript可以使用jQuery的find,依靠parent-child关系,id,...
  • tiplip
  • tiplip
  • 2017年04月06日 11:55
  • 1598

XML——XML解析之DOM

本文介绍了XML解析的基本概念,并重点介绍了使用JAXP的DOM技术进行XML文档的解析...
  • ggGavin
  • ggGavin
  • 2016年06月16日 20:56
  • 1175

Xerces-C++ DOM编程指南(一)

 原文地址:http://xerces.apache.org/xerces-c/program-dom.html设计目标    DOM的C++实现是基于阿帕奇推荐的DOM(Apache Recomme...

xerces dom xml解析

http://xerces.apache.org/xerces-c/program-dom-3.html#UsingDOMAPI 有三种解析器:XercesDOMParser,DOMLSParse...

XML解析简介及Xerces-C++简单使用举例

XML是由World WideWeb联盟(W3C)定义的元语言。它已经成为一种通用的数据交换格式,它的平台无关性,语言无关性,系统无关性,给数据集成与交互带来了极大的方便。XML在不同的语言里解析方式...

xerces C/C++ 读取XML文件的一个小例子

main.cpp #include #include #include #include #include #include // Other include ...

C++中Xerces解析xml文档

Xerces-C++的前身是IBM的XML4C   项目。XML4C和XML4J是两个并列的项目,而XML4J是Xerces-J——Java   实现——的前身。IBM将这两个项目的源代码让与Apac...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Xerces C++ DOM解析XML文档
举报原因:
原因补充:

(最多只允许输入30个字)