`
java-mans
  • 浏览: 11341571 次
文章分类
社区版块
存档分类
最新评论

Xerces C++ DOM解析XML文档

 
阅读更多

前一阵子学习Xerces-C++用于解析指定格式XML文档。在这里,把自己的学习经历和大家分享一下,在这里仅仅讲一些入门的知识,希望对大家有所帮助。

Xerces-C++是什么?

Xerces-C++的前身是 IBM 的XML4C 项目。XML4C 和 XML4J 是两个并列的项目,而 XML4J 是 Xerces-J——Java 实现——的前身。IBM 将这两个项目的源代码让与 Apache 软件基金会(Apache SoftwareFoundation),他们将其分别改名为 Xerces-C++ 和 Xerces-J。这两个项目是 ApacheXML 组的核心项目(如果看到的是“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 EnterpriseLinux AS3,选用的Xerces-C++ 是xerces-c-src_2_7_0.tar.gz,可以从官方网站:http://www.apache.org/ 直接下载。

2、编译源码

由于我下载下来的是源码,所以需要对其进行编译,否则我们无法加载库文件。

首先进入你的工作目录:cd /home/olcom/laubo(这是我当前工作目录)

然后解压你的源码包: tarzxvf 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 unsignedint XMLCh)格式的,一个字符占用一个字节,而汉字字符确要占用两个字节。故若不做适当的转换,汉字的输出结果就变成乱码了。在http://www.vckbase.com/document/viewdoc/?id=738 提供了一种解决的方法,但是那个解决方案只有在locale环境为UTF-8的情况下你才可以看见正常的中文输出,在locale为GB18030等环境下,你的中文是乱码。但是在一种环境下可以正常显示,说明已经可以正常解析出来了,只是在不同环境的机器上需要进行码型转换,因此,我在他提供的类中又添加了两种方法,来进行码型转换:

boolTranslatorUTF8ToChinese(string&strTranslatorMsg);//实现从UTF-8到GBK、GB2312等码型的转换

boolUTF8_2_GB2312(char *in, intinLen, 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 TypeDefinition,DTD)方面有很好的支持,并且在2001年12月增加了支持W3C XML Schema

的基本完整的开放标准。

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

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

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


分享到:
评论

相关推荐

    Xerces-C++

    Xerces-C++ XML解析Xerces-C++ Xerces-C++ DOM编程指南

    xerces-c++-3.1.3

    Xerces分析器可处理Java和C++,它采用互联网联盟XML、文件对象模型以及用于XML的简单API标准。所有的Xerces分析器都是模块化可配置的。它为C++版本提供了Perl封装,允许访问Perl的XML分析器,它还提供对统一编码字符...

    xerces src_2_8_0

    C++开源的xml解析器,当前最新的版本xerces-c-src_2_8_0。Xerces-C++ 的前身是 IBM 的 XML4C 项目。XML4C 和 XML4J 是两个并列的...Xerces-C++是一个非常健壮的 XML 解析器,其提供的两种解析XML文档的方法,DOM和SAX。

    开源xml解析库TingXml。

    常见C/C++ XML解析器有Tinyxml、XERCES、squashxml、xmlite、pugxml、libxml等等,这些解析器有些是支持多语言的,有些只是单纯C/C++的。 TinyXML是目前非常流行的一款基于DOM模型的XML解析器,简单易用且小巧玲珑,...

    xml dom,sax解析,schema验证

    xerces-c++ 2.8应用,主要报错xml文件的解析,创建,修改保存。schema验证的。希望对初学者有所帮助.

    MacOS:Xerces

    Xerces-C++ is a validating XML parser written in a portable subset of C++. Xerces-C++ makes it easy to give your application the ability to read and write XML data. A shared library is provided for ...

    d2school-Xerces-C++编译库part01

    Xerces-C++ (通常也称为:Xerces-C)是一套健壮、强大(同时也很庞大)的 XML 解析库,它提供了验证,以及 SAX 和 DOM API。来源:http://www.d2school.com/

    d2school-Xerces-C++编译库part02

    Xerces-C++ (通常也称为:Xerces-C)是一套健壮、强大(同时也很庞大)的 XML 解析库,它提供了验证,以及 SAX 和 DOM API。来源:http://www.d2school.com/

    xerces-c-3.0.0.zip

    Xerces-C++ is a validating XML parser written in a portable subset of C++. Xerces-C++ makes it easy to give your application the ability to read and write XML data. A shared library is provided for ...

    vs2008编译的xerces_c_3_1_1库

    Xerces-C是用可移植的C++子集编写的XML分析器。Xerces-C允许对XML数据进行读写操作。其特征及功能包括:兼容XML 1.0,能记录最近的DOM和SAX规范,可编程产生和验证XML,具有可内插的目录,具有验证和编码器,进行可...

    xerces-c-src_2_8_0.tar.gz

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

    xerces-c-src-current.zip

    C++版本,解析XML的库,支持DOM和SAX两种形式

    C++开源程序库 C++开源程序库

    其中基于DOM的有TinyXml,基于SAX的当然是Xerces。前者小巧快捷,便于使用,适合做数据交换。后者则是全功能的XML解析器。 7、内存管理:boost::smart_ptr,Hans-Boehm GC C/C++的内存管理是一个永恒的话题。...

    XML DSIG and Encryption (C++)-开源

    一个实现XML DSIG和XML加密标准的C ++库。 基于Apache项目的Xerces(DOM / SAX解析器)和Xalan(XSL / XPATH处理器)库。

    C++标准库介绍.pdf

     Xalan是个用于把XML文档转换为HTML纯文本或者其他XML类型文档XSLT处理器 5、CMarkup 参考网站WebSite:http://www.firstobject.com/xml.htm  这是种使用EDOMXML解析器在很多思路上面非常灵活实用值得大家在DOM和...

Global site tag (gtag.js) - Google Analytics