Showing posts with label Using MSXML to read XML documents. Show all posts
Showing posts with label Using MSXML to read XML documents. Show all posts

Tuesday, March 19, 2013

Read XML using C++


Using this class you can read tag and value of a XML file and add the values in to a std::list.



//ReadXML.h

#include
#include
#include
#include
#import rename_namespace(_T("MSXML"))

class CReadXML
{
public:
CReadXML();
~CReadXML();
HRESULT CreateAndInitDOM(IXMLDOMDocument **ppDoc);
HRESULT VariantFromString(PCWSTR wszValue, VARIANT &Variant);
void LoadDOM( std::string pFileName, std::list>& values );
std::wstring String2WS (const std::string& s);
std::string ConvertWCSToMBS(const wchar_t* pstr, long wslen);
std::string ConvertBSTRToString(BSTR bstr);
BOOL CheckSubNodes( IXMLDOMNode *pNode );
void ReadNodeValues( IXMLDOMNode *pNode, std::list>& values );
void ReadSubNode( IXMLDOMNode *pNode, std::list>& values );

};


//ReadXML.cpp

#include
#include "ReadXML.h"
//http://msdn.microsoft.com/en-us/library/windows/desktop/ms765465(v=vs.85).aspx

// Macro to verify memory allcation.
#define CHK_ALLOC(p)        do { if (!(p)) { hr = E_OUTOFMEMORY; goto CleanUp; } } while(0)

// Macro that calls a COM method returning HRESULT value.
#define CHK_HR(stmt)        do { hr=(stmt); if (FAILED(hr)) goto CleanUp; } while(0)

// Macro that releases a COM object if not NULL.
#define SAFE_RELEASE(p)     do { if ((p)) { (p)->Release(); (p) = NULL; } } while(0)


CReadXML::CReadXML()
{

}

CReadXML::~CReadXML()
{

}

// Helper function to create a DOM instance.
HRESULT CReadXML::CreateAndInitDOM(IXMLDOMDocument **ppDoc)
{

HRESULT hr = CoCreateInstance( __uuidof(MSXML::DOMDocument30), NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void**)ppDoc);
if (SUCCEEDED(hr))
{
// these methods should not fail so don't inspect result
(*ppDoc)->put_async(VARIANT_FALSE);
(*ppDoc)->put_validateOnParse(VARIANT_FALSE);
(*ppDoc)->put_resolveExternals(VARIANT_FALSE);
}
return hr;

//NOT WORKING, IF "xmlns=" IS IN XML FILE
//HRESULT hr = CoCreateInstance(__uuidof(MSXML::DOMDocument60), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(ppDoc));
//   if (SUCCEEDED(hr))
//   {
//       // these methods should not fail so don't inspect result
//       (*ppDoc)->put_async(VARIANT_FALSE);
//       (*ppDoc)->put_validateOnParse(VARIANT_FALSE);
//       (*ppDoc)->put_resolveExternals(VARIANT_FALSE);
//   }


}

// Helper function to create a VT_BSTR variant from a null terminated string.
HRESULT CReadXML::VariantFromString(PCWSTR wszValue, VARIANT &Variant)
{
HRESULT hr = S_OK;
BSTR bstr = SysAllocString(wszValue);
CHK_ALLOC(bstr);

V_VT(&Variant)   = VT_BSTR;
V_BSTR(&Variant) = bstr;

CleanUp:
return hr;
}

std::wstring CReadXML::String2WS (const std::string& s)
{
       std::wstringstream ws;

ws << s.c_str();
std::wstring sLogLevel = ws.str();
return sLogLevel;


// std::wstring ws;
//ws.assign (s.begin (), s.end ());
// return ws;
}

std::string CReadXML::ConvertWCSToMBS(const wchar_t* pstr, long wslen)
{
    int len = ::WideCharToMultiByte(CP_ACP, 0, pstr, wslen, NULL, 0, NULL, NULL);

    std::string dblstr(len, '?');
    len = ::WideCharToMultiByte(CP_ACP, 0 /* no flags */,
                                pstr, wslen /* not necessary NULL-terminated */,
                                &dblstr[0], len,
                                NULL, NULL /* no default char */);

    return dblstr;
}

std::string CReadXML::ConvertBSTRToString(BSTR bstr)
{
    int wslen = ::SysStringLen(bstr);
    return ConvertWCSToMBS((wchar_t*)bstr, wslen);
}

void CReadXML::LoadDOM( std::string pFileName, std::list>& values )
{
HRESULT hr = S_OK;

IXMLDOMDocument *pXMLDom = NULL;
IXMLDOMParseError *pXMLErr = NULL;
IXMLDOMNodeList *NodeList = NULL;
IXMLDOMNode *pNode = NULL;

std::wstring wspFileName;

BSTR bstrXML = NULL;
BSTR bstrErr = NULL;
BSTR bstrQuery2 = NULL;

VARIANT_BOOL varStatus;
VARIANT varFileName;
VariantInit(&varFileName);

//Initialize COM Library:
CoInitialize(NULL);

CHK_HR(CreateAndInitDOM(&pXMLDom));  

wspFileName = String2WS(pFileName);

// XML file name to load
CHK_HR(VariantFromString( wspFileName.c_str(), varFileName));

CHK_HR(pXMLDom->load(varFileName, &varStatus));

if (varStatus == VARIANT_TRUE)
{
CHK_HR(pXMLDom->get_xml(&bstrXML));
//printf("XML DOM loaded from stocks.xml:\n%S\n", bstrXML);

bstrQuery2 = SysAllocString(L"Object"); // For find the tag Object.  Please replace this with your tag name.  If you need to read all values, then replace "Object" with " ".  But the problem is that, then each tags consider as each item, can not separate the child nodes.  For a better out put specify the tag name, where you want to start.

CHK_ALLOC(bstrQuery2);
CHK_HR(pXMLDom->getElementsByTagName(bstrQuery2, &NodeList));

if(NodeList)
{
//get the length of node-set
long length = 0;
CHK_HR(NodeList->get_length(&length));

for (long i = 0; i < length; i++)
{
if ( pNode ) pNode->Release();

CHK_HR( NodeList->get_item(i, &pNode) );

if(pNode )
{
if( CheckSubNodes( pNode ) == TRUE )
{
ReadSubNode( pNode, values );
}
else
{
ReadNodeValues( pNode, values );
}
}
}
}
}
else
{
// Failed to load xml, get last parsing error
CHK_HR(pXMLDom->get_parseError(&pXMLErr));
CHK_HR(pXMLErr->get_reason(&bstrErr));
printf("Failed to load DOM from %S. %S\n", varFileName, bstrErr);
}

CleanUp:
SAFE_RELEASE(pXMLDom);
SAFE_RELEASE(pXMLErr);
SAFE_RELEASE(NodeList);
SAFE_RELEASE(pNode);

SysFreeString(bstrXML);
SysFreeString(bstrErr);
SysFreeString(bstrQuery2);

VariantClear(&varFileName);
}

void CReadXML::ReadSubNode( IXMLDOMNode *pNode, std::list>& values )
{
HRESULT hr = S_OK;
HRESULT hResult;

IXMLDOMNode *pIAttrNode = NULL;
IXMLDOMNodeList *NodeList = NULL;
IXMLDOMNamedNodeMap *pDOMNamedNodeMap = NULL;
long length = 0;
std::pair pPair;

if( pNode )
{
CHK_HR( pNode->get_childNodes(&NodeList) );
if( NodeList )
{
CHK_HR( NodeList->get_length(&length) );

for( int i = 0; i < length; i++ )
{
if (pIAttrNode) pIAttrNode->Release();

CHK_HR( NodeList->get_item(i, &pIAttrNode));

if(pIAttrNode )
{
if( CheckSubNodes( pIAttrNode ) == TRUE )
{
ReadSubNode( pIAttrNode, values );
}
else
{
ReadNodeValues( pIAttrNode, values );
}
}
}
}
}

CleanUp:
SAFE_RELEASE(NodeList);
}

BOOL CReadXML::CheckSubNodes( IXMLDOMNode *pNode )
{
HRESULT hr = S_OK;
IXMLDOMNodeList *NodeList = NULL;
long length = 0;
VARIANT_BOOL varStatus = FALSE;

if( pNode )
{
CHK_HR( pNode->get_childNodes(&NodeList) );
if( NodeList )
{
CHK_HR( NodeList->get_length(&length) );

if( length > 0 )
varStatus = TRUE;
else
varStatus = FALSE;
}
}

CleanUp:
SAFE_RELEASE(NodeList);

return varStatus;
}

void CReadXML::ReadNodeValues( IXMLDOMNode *pNode, std::list>& values )
{
HRESULT hr = S_OK;

IXMLDOMNode* pParNode = NULL;

//Variables to store item's name, parent, text and node type:
BSTR bstrItemText, bstrItemNode, bstrNodeType;
std::pair pPair;

CHK_HR( pNode->get_nodeTypeString(&bstrNodeType));
//We process only elements (nodes of "Text" type):
BSTR temp = L"text";

if (lstrcmp((LPCTSTR)bstrNodeType, (LPCTSTR)temp)==0)
{
CHK_HR( pNode->get_parentNode( &pParNode ) );
if( pParNode )
{
CHK_HR( pParNode->get_nodeName(&bstrItemNode) );
//printf("Text: %ls\n", bstrItemNode);

CHK_HR( pNode->get_text(&bstrItemText) );
//printf("Text: %ls\n", bstrItemText);

pPair.first = ConvertBSTRToString(bstrItemNode);
pPair.second = ConvertBSTRToString(bstrItemText);
values.push_back( pPair);
}
}

CleanUp:
SAFE_RELEASE(pParNode);

}



For using this class create a C++ application and add the above files into that application.  After that create an object of the class "CReadXML" and call the function "LoadDOM".

eg:

        std::list> values;
CReadXML* pCReadXML = new CReadXML();
pCReadXML->LoadDOM("response_tunnel.xml", values);

After the function call you will get the values of XML file in the std::list values!.

Enjoy...!