patterncppMinor
Proper way of using IXMLDOMDocument
Viewed 0 times
properixmldomdocumentwayusing
Problem
I am trying to use IXMLDOMDocument for XML reading/writing. I am not good COM, and I am not aware that I am doing things right or wrong. I am very unsure that there could be some problems with COM initialization and relase. Here is my code below and let me know If there are any possibles bugs / memory leaks here due to COM.
void MyClass::ReadXML(BSTR *pVal)
{
IXMLDOMDocument * pXMLDoc;
IXMLDOMNode * pXDN;
HRESULT hr = CoInitialize(NULL);
hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument, (void**)&pXMLDoc);
if (SUCCEEDED(hr))
{
IXMLDOMNode* pEntityNode = CDOMHelpers::InsertDOMElement(pDoc, NULL, L"Person", NULL);
if (SUCCEEDED(hr))
{
SomeClassObject->SerializeXML(pXMLDoc, pXDN);
pXMLDoc->get_xml(pVal);
pXDN->Release(); // Is this proper way to release COM?
pXDN = NULL;
pXMLDoc->Release();
pXMLDoc = NULL;
}
}
}
void SomeOtherClass::SerializeXML(IXMLDOMDocument* pDoc, IXMLDOMNode* pXDN)
{
CStringW text;
IXMLDOMNode* pNewNode;
text.Format(L"%u", Name);
pNewNode = CDOMHelpers::InsertDOMElement(pDoc, pEntityNode, L"Name", text);
text.Format(L"%u", Address);
pNewNode = CDOMHelpers::InsertDOMElement(pDoc, pEntityNode, L"Address", text);
}Solution
MSDN documentation for this is a mess and for the most part, inadequate (it's better than MSDN's C++ ADO documentation though).
If you have access to MSXML, then you can use smart pointer wrappers that allow you to avoid worrying about releasing the objects. These smart pointers come with simplified function calls.
For instance, here is the normal function prototype for a
Here is the "smart" version of that function for
This allows you skip the error checking (it throws an exception on failure).
You also have access to the source code for these new functions as well. The source code is in an automatically generated
If you have access to
Here are a few examples of using the smart pointers. I used standard library containers such as
If you have access to MSXML, then you can use smart pointer wrappers that allow you to avoid worrying about releasing the objects. These smart pointers come with simplified function calls.
For instance, here is the normal function prototype for a
IXMLDOMNodeList:HRESULT IXMLDOMNodeList::get_length(long *listLength);Here is the "smart" version of that function for
IXMLDOMNodeList object:long IXMLDOMNodeList::Getlength ();This allows you skip the error checking (it throws an exception on failure).
You also have access to the source code for these new functions as well. The source code is in an automatically generated
.tli file, so you can always know what they do. The .tli file is usually located in C:\Users\User\Local\Temp\msxml6.tli. Just looking through this file can help you partially learn how to use IXMLDom. If you have access to
comutil.h, you can use the _bstr_t type instead of BSTR for automatic memory management as well. Here are a few examples of using the smart pointers. I used standard library containers such as
std::string and std::vector, but you could easily change these out with CStrings or other string types. #include
#include
#include
#include
#import
typedef std::basic_string tstring ;
typedef MSXML2::IXMLDOMNodePtr NodePtr ;
typedef MSXML2::IXMLDOMNodeListPtr NodeListPtr ;
typedef MSXML2::IXMLDOMDocumentPtr DocumentPtr ;
typedef MSXML2::IXMLDOMElementPtr ElementPtr ;
typedef MSXML2::IXMLDOMNamedNodeMapPtr NamedNodeMapPtr ;
DocumentPtr LoadXMLDocument (const tstring &strFile)
{
// Call ::CoInitialize or ::CoInitializeEx before this.
HRESULT hr ;
DocumentPtr pDoc = NULL ;
hr = pDoc.CreateInstance (__uuidof (MSXML2::DOMDocument60)) ;
if (hr != S_OK) {
// This could happen if ::CoInitialize or ::CoInitializeEx hasn't been called.
// Throw an exception.
}
pDoc->async = VARIANT_FALSE ;
pDoc->validateOnParse = VARIANT_FALSE ;
pDoc->resolveExternals = VARIANT_FALSE ;
VARIANT_BOOL vbOk = pDoc->load (_variant_t (strFile.data ())) ;
if (vbOk == VARIANT_FALSE) {
// Throw an exception.
}
return pDoc ;
}
tstring GetAttribute (const NamedNodeMapPtr &pAttrs, const tstring &strKey)
{
tstring str ;
NodePtr pAttr = pAttrs->getNamedItem (_bstr_t (strKey.data ())) ;
if (pAttr == NULL) {
// Throw an exception.
}
_variant_t var = pAttr->GetnodeValue () ;
if (var.vt == VT_BSTR) {
str = (TCHAR *) (_bstr_t) var ;
} else {
// Throw an exception.
}
return str ;
}
tstring GetAttribute (const NodePtr &pNode, const tstring &strKey)
{
NamedNodeMapPtr pAttrs = pNode->Getattributes () ;
return GetAttribute (pAttrs, strKey) ;
}
tstring GetSubElementText (const ElementPtr &pNode, const tstring &strSubElement)
{
NodePtr pSub = pNode->selectSingleNode (_bstr_t (strSubElement.data ())) ;
if (pSub == NULL) {
// Throw an exception.
}
_bstr_t bsRoot = pSub->Gettext () ;
tstring strText = (TCHAR *) bsRoot ;
return strText ;
}
void GetAttributes (const NodePtr &pNode, const std::vector &vecKeys, std::vector &vecValues, const tstring &strDefault)
{
NamedNodeMapPtr pAttrs = pNode->Getattributes () ;
for (unsigned n = 0; n < vecKeys.size (); ++n) {
const tstring &strKey = vecKeys [n] ;
tstring str = BVLib::GetAttribute (pAttrs, strKey) ;
vecValues.push_back (str) ;
}
}Code Snippets
HRESULT IXMLDOMNodeList::get_length(long *listLength);long IXMLDOMNodeList::Getlength ();#include <string>
#include <vector>
#include <tchar.h>
#include <comutil.h>
#import <msxml6.dll>
typedef std::basic_string <TCHAR> tstring ;
typedef MSXML2::IXMLDOMNodePtr NodePtr ;
typedef MSXML2::IXMLDOMNodeListPtr NodeListPtr ;
typedef MSXML2::IXMLDOMDocumentPtr DocumentPtr ;
typedef MSXML2::IXMLDOMElementPtr ElementPtr ;
typedef MSXML2::IXMLDOMNamedNodeMapPtr NamedNodeMapPtr ;
DocumentPtr LoadXMLDocument (const tstring &strFile)
{
// Call ::CoInitialize or ::CoInitializeEx before this.
HRESULT hr ;
DocumentPtr pDoc = NULL ;
hr = pDoc.CreateInstance (__uuidof (MSXML2::DOMDocument60)) ;
if (hr != S_OK) {
// This could happen if ::CoInitialize or ::CoInitializeEx hasn't been called.
// Throw an exception.
}
pDoc->async = VARIANT_FALSE ;
pDoc->validateOnParse = VARIANT_FALSE ;
pDoc->resolveExternals = VARIANT_FALSE ;
VARIANT_BOOL vbOk = pDoc->load (_variant_t (strFile.data ())) ;
if (vbOk == VARIANT_FALSE) {
// Throw an exception.
}
return pDoc ;
}
tstring GetAttribute (const NamedNodeMapPtr &pAttrs, const tstring &strKey)
{
tstring str ;
NodePtr pAttr = pAttrs->getNamedItem (_bstr_t (strKey.data ())) ;
if (pAttr == NULL) {
// Throw an exception.
}
_variant_t var = pAttr->GetnodeValue () ;
if (var.vt == VT_BSTR) {
str = (TCHAR *) (_bstr_t) var ;
} else {
// Throw an exception.
}
return str ;
}
tstring GetAttribute (const NodePtr &pNode, const tstring &strKey)
{
NamedNodeMapPtr pAttrs = pNode->Getattributes () ;
return GetAttribute (pAttrs, strKey) ;
}
tstring GetSubElementText (const ElementPtr &pNode, const tstring &strSubElement)
{
NodePtr pSub = pNode->selectSingleNode (_bstr_t (strSubElement.data ())) ;
if (pSub == NULL) {
// Throw an exception.
}
_bstr_t bsRoot = pSub->Gettext () ;
tstring strText = (TCHAR *) bsRoot ;
return strText ;
}
void GetAttributes (const NodePtr &pNode, const std::vector <tstring> &vecKeys, std::vector <tstring> &vecValues, const tstring &strDefault)
{
NamedNodeMapPtr pAttrs = pNode->Getattributes () ;
for (unsigned n = 0; n < vecKeys.size (); ++n) {
const tstring &strKey = vecKeys [n] ;
tstring str = BVLib::GetAttribute (pAttrs, strKey) ;
vecValues.push_back (str) ;
}
}Context
StackExchange Code Review Q#31084, answer score: 5
Revisions (0)
No revisions yet.