2009-01-21 7 views
6

No es realmente una pregunta porque ya he encontrado una solución. Me tomó mucho tiempo, es por eso que quiero explicarlo aquí.¿Cómo usar msxml con Visual Studio 2008 Express (sin clases ATL) sin volverse loco?

Msxml está basado en COM por lo que no es realmente fácil de usar en C++ incluso cuando tiene clases útiles para tratar problemas de asignación de memoria. Pero escribir un nuevo analizador XML sería mucho más difícil, así que quería usar msxml.

El problema:

pude encontrar suficientes ejemplos en el Internet para utilizar msxml con la ayuda de CComPtr (puntero inteligente para no tener que llamar a Release() para cada IXMLDOMNode manualmente), CComBSTR (para convertir cadenas de C++ al formato COM para cadenas) y CComVariant. Estas 3 clases útiles son clases ATL y necesitan un #include <atlbase.h>.

Problema: Visual Studio 2008 Express (la versión gratuita) no incluye ATL.

Solución:

Uso comutil.h y comdef.h, que incluyen algunas clases de ayuda simples:

  • _bstr_t reemplaza más o menos CComBSTR
  • _variant_t reemplaza más o menos CComVariant
  • _com_ptr_t sustituye indirectamente CComPtr mediante el uso de _COM_SMARTPTR_TYPEDEF

ejemplo Pequeño:

#include <msxml.h> 
#include <comdef.h> 
#include <comutil.h> 

// Define some smart pointers for MSXML 
_COM_SMARTPTR_TYPEDEF(IXMLDOMDocument,  __uuidof(IXMLDOMDocument));  // IXMLDOMDocumentPtr 
_COM_SMARTPTR_TYPEDEF(IXMLDOMElement,  __uuidof(IXMLDOMElement));  // IXMLDOMElementPtr 
_COM_SMARTPTR_TYPEDEF(IXMLDOMNodeList,  __uuidof(IXMLDOMNodeList));  // IXMLDOMNodeListPtr 
_COM_SMARTPTR_TYPEDEF(IXMLDOMNamedNodeMap, __uuidof(IXMLDOMNamedNodeMap)); // IXMLDOMNamedNodeMapPtr 
_COM_SMARTPTR_TYPEDEF(IXMLDOMNode,   __uuidof(IXMLDOMNode));   // IXMLDOMNodePtr 

void test_msxml() 
{ 
    // This program will use COM 
    CoInitializeEx(NULL, COINIT_MULTITHREADED); 

    { 
     // Create parser 
     IXMLDOMDocumentPtr pXMLDoc; 
     HRESULT hr = CoCreateInstance(__uuidof (DOMDocument), NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void**)&pXMLDoc); 
     pXMLDoc->put_validateOnParse(VARIANT_FALSE); 
     pXMLDoc->put_resolveExternals(VARIANT_FALSE); 
     pXMLDoc->put_preserveWhiteSpace(VARIANT_FALSE); 

     // Open file 
     VARIANT_BOOL bLoadOk; 
     std::wstring sfilename = L"testfile.xml"; 
     hr = pXMLDoc->load(_variant_t(sfilename.c_str()), &bLoadOk); 

     // Search for node <testtag> 
     IXMLDOMNodePtr pNode; 
     hr = pXMLDoc->selectSingleNode(_bstr_t(L"testtag"), &pNode); 

     // Read something 
     _bstr_t bstrText; 
     hr = pNode->get_text(bstrText.GetAddress()); 
     std::string sSomething = bstrText; 
    } 

    // I'm finished with COM 
    // (Don't call before all IXMLDOMNodePtr are out of scope) 
    CoUninitialize(); 
} 
+0

VS2008 express no incluye ATL? eso apesta. > :( –

Respuesta

1

Estoy feliz de haber publicado mi pregunta, aunque ya tenía una solución porque obtuve varias soluciones alternativas. Gracias por todas sus respuestas.

El uso de otro programa de análisis tales como eXpat o tal vez el más pequeño (no tan potente, pero suficiente para mis necesidades) TinyXML en realidad podría ser una buena idea (y que sea más fácil para portar el programa a otro sistema operativo).

Usando una directiva #import, al parecer una extensión específica de Microsoft para simplificar el uso de COM, también es interesante y me llevó a la siguiente página web MSXML in C++ but as elegant as in C#, que explican cómo simplificar el uso de msxml tanto como sea posible.

1

Otra opción sería utilizar otro analizador XML que ya está hecho, such as eXpat. Evita tener que usar ATL y las complejidades de COM, y es mucho más fácil que implementar el tuyo. Sugiero esto solo porque ha declarado que la razón por la que está mirando a msxml es porque no desea implementar su propio analizador.

+0

Ya pensé en usar eXpat, pero como msxml ya estaba en la computadora, pensé que usarlo podría ayudar a hacer un programa más pequeño. Pero si hubiera sabido antes sobre las dificultades COM, podría haber usado eXpat ... . – Name

7

Quizás intente utilizar la instrucción #import.

Lo he utilizado en un proyecto VS6 He dando vueltas, se hace algo como esto (sólo para fines ilustrativos; esto funcionó para mí, pero yo no pretendo ser a prueba de errores):

#import "msxml6.dll" 

    ... 

MSXML2::IXMLDOMDocument2Ptr pdoc; 
HRESULT hr = pdoc.CreateInstance(__uuidof(MSXML2::DOMDocument60)); 
if (!SUCCEEDED(hr)) return hr; 

MSXML2::IXMLDOMDocument2Ptr pschema; 
HRESULT hr = pschema.CreateInstance(__uuidof(MSXML2::DOMDocument60)); 
if (!SUCCEEDED(hr)) return hr; 

pschema->async=VARIANT_FALSE; 
VARIANT_BOOL b; 
b = pschema->loadXML(_bstr_t(/* your schema XML here */)); 

MSXML2::IXMLDOMSchemaCollection2Ptr pSchemaCache; 
hr = pSchemaCache.CreateInstance(__uuidof(MSXML2::XMLSchemaCache60)); 
if (!SUCCEEDED(hr)) return hr; 

_variant_t vp=pschema.GetInterfacePtr(); 
pSchemaCache->add(_bstr_t(/* your namespace here */),vp); 

pdoc->async=VARIANT_FALSE; 
pdoc->schemas = pSchemaCache.GetInterfacePtr(); 
pdoc->validateOnParse=VARIANT_TRUE; 
if (how == e_filename) 
    b = pdoc->load(v); 
else 
    b = pdoc->loadXML(bxmldoc); 

pXMLError = pdoc->parseError; 
if (pXMLError->errorCode != 0) 
    return E_FAIL; // an unhelpful return code, sigh.... 
+0

#import es la mejor manera de hacerlo, fácil y muy poco código para escribir por usted mismo – galets

+0

No había escuchado sobre "#import" antes de ahora (con C++ he pasado más tiempo bajo Unix que bajo Windows hasta ahora). Parece ser bastante interesante. – Name

0

¿Por qué no utiliza un contenedor MSXML que lo protegería de COM, como Arabica?

+0

Gracias por su respuesta. Pero realmente no quiero agregar una capa de direccionamiento indirecto para usar el analizador XML. – Name

1

Puede usar TinyXML. Es de código abierto y más independiente de la plataforma.

+0

Interesante, no había escuchado sobre este analizador antes. Podría ser una "luz". "alternativa a eXpat (a través de no he comprobado cuántos recursos necesita eXpat). – Name

Cuestiones relacionadas