Способы разбора XML в C ++ (Win32) - PullRequest
4 голосов
/ 20 июня 2010

Я ищу способ синтаксического анализа XML в C ++ в Windows, и нашел несколько таких, как MSXML, Xerces, TinyXml и т. Д., Но мне интересно, какой из них является лучшим с точки зрения производительности и возможностей. Мои требования заключаются в том, что он должен быть статически связан или иметь источник, включенный в сам проект, и не должен требовать каких-либо дополнительных инструментов, таких как boost. MSXML был бы очевидным выбором, поскольку это библиотека MS, но она, кажется, является библиотекой COM и довольно сложна для того, чтобы на самом деле извлечь из нее какую-либо пользу.

Есть ли у кого-нибудь предложения относительно того, что можно быстро и просто использовать?

Спасибо, J

Ответы [ 5 ]

4 голосов
/ 20 июня 2010

Я успешно использовал libxml.API немного запутанный и сложный, но как только вы его получите, он работает довольно хорошо.Кроме того, он наполнен функциональностью, поэтому, если вам это нужно, используйте libxml.Вам не нужно беспокоиться о раздутых двоичных файлах, поскольку вы можете связывать только те части, которые вам нужны.Вам не нужно включать полный libxml, если вам нужно только разобрать xml и не использовать xpath, например

2 голосов
/ 06 сентября 2011

Поскольку все поддерживаемые версии 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 ) );
}
2 голосов
/ 20 июня 2010

Лучшая библиотека, которую я использовал и которая абсолютно прозрачна в терминах использования и понимания, была pugixml.

Чрезвычайно легкий, очень быстрый, гибкий и удобный - что еще можно ожидать?

1 голос
/ 21 июня 2010

Папа XML-парсеров в супертяжелом весе: Xerces
Более простой анализатор Expat Есть C ++ оболочки вокруг.

Вокруг много XML-парсеров.
Быстрый Google найдет вас достаточно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...