zoukankan      html  css  js  c++  java
  • [zz]XercesC++ 参考

    个人总结:

    注意 SAX 和 DOM的区别

    遍历方法

    DOMElement *pRoot = xmlDoc->getDocumentElement()。

    一种是创建遍历树 DOMTreeWalker *walker = xmlDoc->createTreeWalker(pRoot, DOMNodeFilter::SHOW_TEXT, NULL, true),还有一种是通过迭代器来遍历整棵DOM树 DOMNodeIterator* iterator = xmlDoc->createNodeIterator(pRoot,    DOMNodeFilter::SHOW_TEXT,  NULL, true)。两种方法都可以达到同样的效果。程序中注释掉的代码是创建遍历树方法。

    也可以xmlDoc->getElementByTagName()

    本文还有 XMLCh 与 string的相互转化方法

    ---------------------------------------------------------------我是无情的分割线--------------------------------------------------------------

    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>
          </国家调查>
          定义好格式后,我们来看看程序是如何实现对其解析的,程序如下:


    //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++类库。

  • 相关阅读:
    C语言实现单处理器的进程管理
    哈夫曼编码
    栈与队列的应用:停车场管理
    带括号的表达式求值
    表达式求值(无括号)
    处理代码异常
    在Pyhon中使用:网络编程 & 接口开发
    枚举函数(enumerate)
    【Redis】数据库相关操作
    数据库(新增数据、建立数据表、复制、对比表数据)
  • 原文地址:https://www.cnblogs.com/zhangzhang/p/2442464.html
Copyright © 2011-2022 走看看