【问题标题】:Ways to parse XML in C++ (Win32)在 C++ (Win32) 中解析 XML 的方法
【发布时间】:2010-06-20 17:32:55
【问题描述】:

我正在寻找一种在 Windows 中用 C++ 解析 XML 的方法,我发现了一些方法,例如 MSXML、Xerces、TinyXml 等,但我想知道哪种方法在性能和功能方面最好。我的要求是它必须能够静态链接或将源包含在项目本身中,并且不得需要任何额外的工具,例如 boost。 MSXML 将是一个显而易见的选择,因为它是一个 MS 库,但它似乎是一个 COM 库,而且相当复杂,无法真正从中获得任何用途。

有没有人对快速简单的使用有什么建议?

谢谢, J

【问题讨论】:

    标签: c++ windows xml winapi


    【解决方案1】:

    我成功使用了 libxml。 API 有点混乱和复杂,但是一旦你得到它,它就可以很好地工作。此外它充满了功能,所以如果你需要它,请使用 libxml。 您不必担心臃肿的二进制文件,因为您只能链接您需要的部分。如果您只需要解析 xml 并且不使用 xpath 的东西,则不需要包含完整的 libxml

    【讨论】:

    • 完美!我刚刚检查了 libxml2,它正是我正在寻找的,我很快就启动并运行了它。谢谢。
    【解决方案2】:

    由于所有受支持的 Windows 版本(包括 Windows XP SP3)都包含 MSXML 6.0,因此您应该使用 MS XML 6.0。你应该实现自己的ISAXContentHandler 类,通常我实现一个ISequentialStream 类。

    用于解析的 ISequentialStream 实现:

    class MySequentialStream : public ISequentialStream
    {
    public:
      MySequentialStream( istream &is )
        : is(is), ref_count(0)
      {
        InitializeCriticalSection( &this->critical_section );
      };
      virtual ~MySequentialStream( void )
      {
        DeleteCriticalSection( &this->critical_section );
      }
      virtual HRESULT __stdcall QueryInterface( const IID &riid, void ** ppvObject )
      {
        if ( riid == IID_ISequentialStream )
        {
          *ppvObject = static_cast<void*>(this);
          this->AddRef();
          return S_OK;
        }
        if (riid == IID_IUnknown)
        {
          *ppvObject = static_cast<void*>(this);
          this->AddRef();
          return S_OK;
        }
        *ppvObject = 0;
        return E_NOINTERFACE;
      };
      virtual ULONG __stdcall AddRef( void )
      {
        return InterlockedIncrement(&this->ref_count);
      };
      virtual ULONG __stdcall Release( void )
      {
        ULONG nRefCount = InterlockedDecrement(&this->ref_count);
        if ( nRefCount == 0 ) delete this;
        return nRefCount;
      };    
      virtual HRESULT __stdcall Read( void *pv, ULONG cb, ULONG *pcbRead )
      {
        EnterCriticalSection( &this->critical_section );
        this->is.read( reinterpret_cast<char*>(pv), cb );
        *pcbRead = static_cast<ULONG>( this->is.gcount() );
        LeaveCriticalSection( &this->critical_section );
        return S_OK;
      };
      virtual HRESULT __stdcall Write( void const *pv, ULONG cb, ULONG *pcbWritten )
      {
        *pcbWritten = cb;
        return S_OK;
      };    
    private:
      istream &is;
      CRITICAL_SECTION critical_section;
      ULONG ref_count;
    };
    

    你也应该实现一个 ISAXContentHandler 类(当然你应该在需要的时候填充方法):

    class MyContentHandler : public ISAXContentHandler
    {
    public:
      MyContentHandler( void )
        : ref_count(0)
      {};
      virtual ~MyContentHandler( void ) {};
      virtual HRESULT __stdcall QueryInterface( const IID &riid, void ** ppvObject )
      {
        if ( riid == __uuidof(ISAXContentHandler) )
        {
          *ppvObject = static_cast<void*>(this);
          this->AddRef();
          return S_OK;
        }
        if (riid == IID_IUnknown)
        {
          *ppvObject = static_cast<void*>(this);
          this->AddRef();
          return S_OK;
        }
        *ppvObject = 0;
        return E_NOINTERFACE;
      };
      virtual ULONG __stdcall AddRef( void )
      {
        return InterlockedIncrement(&this->ref_count);
      };
      virtual ULONG __stdcall Release( void )
      {
        ULONG nRefCount = InterlockedDecrement(&this->ref_count);
        if ( nRefCount == 0 ) delete this;
        return nRefCount;
      };    
      virtual HRESULT __stdcall putDocumentLocator( ISAXLocator * pLocator) { return S_OK; };
      virtual HRESULT __stdcall startDocument( void ) { return S_OK; };
      virtual HRESULT __stdcall endDocument( void ) { return S_OK; };
      virtual HRESULT __stdcall startPrefixMapping( const wchar_t *pwchPrefix, int cchPrefix, const wchar_t *pwchUri, int cchUri ) { return S_OK; };
      virtual HRESULT __stdcall endPrefixMapping( const wchar_t *pwchPrefix, int cchPrefix) { return S_OK; };
      virtual HRESULT __stdcall startElement( const wchar_t *pwchNamespaceUri, int cchNamespaceUri, const wchar_t *pwchLocalName, int cchLocalName, const wchar_t *pwchQName, int cchQName, ISAXAttributes *pAttributes ) { return S_OK; };
      virtual HRESULT __stdcall endElement( const wchar_t *pwchNamespaceUri, int cchNamespaceUri, const wchar_t *pwchLocalName, int cchLocalName, const wchar_t *pwchQName, int cchQName) { return S_OK; };
      virtual HRESULT __stdcall characters( const wchar_t *pwchChars, int cchChars) { return S_OK; };
      virtual HRESULT __stdcall ignorableWhitespace( const wchar_t *pwchChars, int cchChars) { return S_OK; };
      virtual HRESULT __stdcall processingInstruction( const wchar_t *pwchTarget, int cchTarget, const wchar_t *pwchData, int cchData) { return S_OK; };
      virtual HRESULT __stdcall skippedEntity( const wchar_t *pwchName, int cchName) { return S_OK; };
    protected:
      ULONG ref_count;
    };
    

    然后你可以很容易地解析一个流:

    bool ParseStream( istream &is )
    {
      if ( FAILED(CoInitialize(NULL)) )
       return false;
    
      ISAXXMLReader * reader = 0;
      if ( FAILED( CoCreateInstance( __uuidof(SAXXMLReader60), NULL, CLSCTX_ALL, __uuidof(ISAXXMLReader),(void**) &reader ) ) )
      {
       CoUninitialize()
       return false;
      }
    
      ISequentialStream * my_stream = new MySequentialStream(is);
      ISAXContentHandler * content_handler = new MyContentHandler;
    
      my_stream->AddRef();
      content_handler->AddRef();
    
      if ( FAILED( reader->putContentHandler( content_handler ) ) )
      {
       my_stream->Release();
       content_handler->Release();
       reader->Release();
       return false;
      }
    
      VARIANT var;
      var.vt = VT_UNKNOWN;
      var.punkVal = my_stream;
      VARIANT_BOOL success = FALSE;
    
      bool value = SUCCEEDED( reader->parse( var ) );
    
      my_stream->Release();
      content_handler->Release();
      reader->Release();
      return ( value && ( success != VARIANT_FALSE ) );
    }
    

    【讨论】:

      【解决方案3】:

      我用过的最好的库是pugixml.

      极其轻量级、非常快速、灵活和方便 - 还有什么可以期待的?

      【讨论】:

        【解决方案4】:

        【讨论】:

        • 想详细说明“......可能是最好和最容易使用的”部分?我猜都试过了?
        【解决方案5】:

        XML 解析器的重量级老爹是Xerces
        一个更简单更容易的解析器Expat 周围有C++ wrappers

        周围有很多 XML 解析器。
        快速的 Google 会找到很多。

        【讨论】:

          猜你喜欢
          • 2011-03-04
          • 1970-01-01
          • 2011-01-24
          • 1970-01-01
          • 1970-01-01
          • 2013-09-01
          • 1970-01-01
          • 2014-04-15
          • 1970-01-01
          相关资源
          最近更新 更多