在C ++中解析XML的方法(Win32)

时间:2010-06-20 17:32:55

标签: c++ windows xml winapi

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

有没有人对快速和简单易用的东西有任何建议?

谢谢, Ĵ

5 个答案:

答案 0 :(得分:4)

我成功使用了libxml。 API有点令人困惑和复杂,但一旦你得到它它的效果非常好。除了它充满了功能,所以如果你需要它,请使用libxml。 你不必担心臃肿的二进制文件,因为你只能链接你需要的部分。如果你只需要解析xml并且不使用xpath的东西,你就不需要包含完整的libxml

答案 1 :(得分:2)

我使用过的最好的库,在使用和理解术语中绝对透明pugixml.

非常轻巧,非常快速,灵活和方便 - 还有什么可以期待?

答案 2 :(得分: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 :(得分:1)

答案 4 :(得分:1)

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

周围有很多XML解析器 一个快速的谷歌会发现你很多。