XML parsing to get a value of a single node

I have never done XML parsing in VC++ so I thought I would ask this here as it would save me some time.

I call a web service and store the XML that is returned in a _bstr_t.

The XML looks like this (The carriage returns are not actually there, i just put them in for visability):

<?xml version=1.0>
<ADSearchResult>
  <User>
    <mail>someone@somewhere.ca</mail>
  </User>
</ADSearchResult>

I need to get the value in the <mail> node.  How would I do this in VC++?


Thanks,

Leo
LVL 8
Leo EikelmanDirector, IT and Business DevelopmentAsked:
Who is Participating?
 
Dariusz DziaraConnect With a Mentor ProgrammerCommented:
The following is from MSDN (find the topic itself):

#define UNICODE

#include <windows.h>
#include <windowsx.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <urlmon.h>
#include <hlink.h>
#include <dispex.h>
#include "mshtml.h"
#include "msxml.h"

#define ASSERT(x)  if(!(x)) DebugBreak()
#define CHECK_ERROR(cond, err) if (!(cond)) {pszErr=(err); goto done;}
#define SAFERELEASE(p) if (p) {(p)->Release(); p = NULL;} else ;


int _cdecl main (int argc, char **argv)
{
    PSTR pszErr = NULL;
    IXMLDocument           *pDoc = NULL;
    IStream                *pStm = NULL;
    IPersistStreamInit     *pPSI = NULL;
    CHAR                   buf[MAX_PATH];
    CHAR                   *pszURL;

    HRESULT hr;

    //
    // Check usage.
    //
    if (argc != 2)
    {
        fprintf (stderr, "Usage:   %s URL\n", argv[0]);
        fprintf (stderr, "Eg %s c:\\nt\\private\\inet\\xml\\test\\channel.cdf\n", argv[0]);
        fprintf (stderr, "or %s http://ohserv/users/julianj/msnbc.cdf\n", argv[0]);
        exit (1);
    }

    //
    // HACK if passed in a file name; expand if it doesn't look like a URL.
    //
    if (CompareStringA(LOCALE_USER_DEFAULT, NORM_IGNORECASE, argv[1], 7, "http://", 7) == CSTR_EQUAL)
    {
        pszURL = argv[1];
    }
    else
    {
        pszURL = buf;
        GetFullPathNameA(argv[1], MAX_PATH, pszURL, NULL);
    }

    hr = CoInitialize(NULL);
    ASSERT(SUCCEEDED(hr));

    //
    // Create an empty XML document.
    //
    hr = CoCreateInstance(CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER,
                                IID_IXMLDocument, (void**)&pDoc);

    CHECK_ERROR (pDoc, "CoCreateInstance Failed");

    //
    // Synchronously create a stream on a URL.
    //
    hr = URLOpenBlockingStreamA(0, pszURL, &pStm, 0,0);    
    CHECK_ERROR(SUCCEEDED(hr) && pStm, "Couldn't open stream on URL")
    //
    // Get the IPersistStreamInit interface to the XML doc.
    //
    hr = pDoc->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI);
    CHECK_ERROR(SUCCEEDED(hr), "QI for IPersistStreamInit failed");

    //
    // Init the XML doc from the stream.
    //
    hr = pPSI->Load(pStm);
    //CHECK_ERROR(SUCCEEDED(hr), "Couldn't load XML doc from stream");

    if(SUCCEEDED(hr))
    {
        printf("%s : XML File is well formed \r\n",argv[0]);

    }
    else
    {
        // Print error information !
        IXMLError *pXMLError = NULL ;
        XML_ERROR xmle;

        hr = pPSI->QueryInterface(IID_IXMLError, (void **)&pXMLError);
        CHECK_ERROR(SUCCEEDED(hr), "Couldn't get IXMLError");

        ASSERT(pXMLError);

        hr = pXMLError->GetErrorInfo(&xmle);
        SAFERELEASE(pXMLError);
        CHECK_ERROR(SUCCEEDED(hr), "GetErrorInfo Failed");

        printf("%s :", argv[0]);
        wprintf(TEXT(" Error on line %d. Found %s while expecting %s\r\n"),
                            xmle._nLine,
                            xmle._pszFound,
                            xmle._pszExpected);
       
        SysFreeString(xmle._pszFound);
        SysFreeString(xmle._pszExpected);
        SysFreeString(xmle._pchBuf);
    }

done: // Clean up.
    //
    // Release any used interfaces.
    //
    SAFERELEASE(pPSI);
    SAFERELEASE(pStm);
    SAFERELEASE(pDoc);

    if (pszErr)
        fprintf (stderr, "%s, last error %d\n", pszErr, GetLastError());
    return 0;
}

0
 
Leo EikelmanDirector, IT and Business DevelopmentAuthor Commented:
This talks about getting a Stream from a URL by the looks of it...

All I want is a simple code to parse a string that is formatted as XML and retrieve data from a node..

The above looks too complicated for such a small task.

Leo
0
 
Dariusz DziaraProgrammerCommented:
It doen't seem too complex for me (remove error checking) ;)

You can use:

HGLOBAL hMem;
IStream *pIStream;

CreateStreamOnHGlobal(hMem, TRUE, &pIStream); // create memory based stream

pIStream->Write(data, size, &bytes);        // write your string to memory IStream here

[...]

pIStream->Release();
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
Leo EikelmanDirector, IT and Business DevelopmentAuthor Commented:
I would prefer a solution that uses MSXML (msxml4.dll)

Leo
0
 
Leo EikelmanDirector, IT and Business DevelopmentAuthor Commented:
Ok I found the solution using msxml4.dll

Thanks,

Leo
0
 
Dariusz DziaraProgrammerCommented:
I don't want to frighten you but it will be necessary to parse data at the end.

IXMLElement *pElem;
IXMLElementCollection *pCol;
IDispatch *pDisp;

pDoc->get_root(&pElem);

pElem->get_children(&pCol);

pCol->get_length(&nCount);

for(i=0; i<nCount; i++) {
  pCol->item(vIndx1, vIndx2, &pDisp);
  pDisp->QueryInterface(IID_XMLElement, &pElemNested);  

  // and similar things
}

pCol->Release();
pElem->Release();
0
 
Leo EikelmanDirector, IT and Business DevelopmentAuthor Commented:
Actually my solution was much simplier because I am only dealing with a single node that will have only one value.  It looks like this:

MSXML2::IXMLDOMDocumentPtr xmlDoc("MSXML2.DOMDocument.4.0");
      xmlDoc->async = false;
    short ret = xmlDoc->loadXML(st1);
       if ( ret)
    {
      printf("Document loaded ok.");
    }
    else
    {
       printf("load problem");
    }
   
      IXMLDOMNodePtr pNode = xmlDoc->selectSingleNode("//mail");
      printf(pNode->firstChild->text);

Thanks,

Leo
0
 
Dariusz DziaraProgrammerCommented:
You can simplify thing using VC++ native COM support (you will avoid remembering about ->Release() call).

instead of:
IXMLElement *pElem;

declare

IXMLElementPtr pElem;
0
All Courses

From novice to tech pro — start learning today.