|
Summary |
 |
This sample application illustrates the MSXML 4.0 DOM API. This is a Visual C++ 6.0 Win32 console application that uses MSXML 4.0 to load a remote or local XML document, adds an attribute to the document‘s root element; then uses XPath to search for a node, if found, updates the node‘s value with the current datetime, else creates a new node and sets its value. |
|
Steps |
 |
Steps that we followed to create this application:
1. |
Start Visual C++ 6.0 and create a new Win32 Console Application project. |
2. |
Add the following lines in the stdafx.h:
#include <TCHAR.H>
#include <stdio.h>
#include <time.h>
#import "msxml4.dll"
// ^^^^^^^^^^^^
// If this import statement fails, you need to install MSXML 4.0 SP1 from:
//
// http://msdn.microsoft.com/downloads/sample.asp?url=/MSDN-FILES/027/001/766/msdncompositedoc.xml
#include <msxml2.h>
// ^^^^^^^^^^
// If this include statement fails, you need to install MSXML 4.0 SP1 SDK from:
//
// http://msdn.microsoft.com/downloads/sample.asp?url=/MSDN-FILES/027/001/766/msdncompositedoc.xml
//
// You also need to add the include file and library search path
// to Visual C++‘s list of directories (Tools > Options... > Directories).
using namespace MSXML2;
inline void EVAL_HR( HRESULT _hr )
{ if FAILED(_hr) throw(_hr); }
|
3. |
The above lines import the MSXML 4 type library, include the MSXML header file, and contain a tiny utility function to check the HRESULT value. |
4. |
The main function looks like as below:
int main(int argc, char* argv[])
{
try
{
EVAL_HR(CoInitialize(NULL));
// Make sure MSXML 4.0 is installed
if (!isMSXMLInstalled())
return -1;
IXMLDOMDocument2Ptr pXMLDoc = NULL;
TCHAR szHTTPURL[MAX_PATH] = {0};
_tcscpy(szHTTPURL, g_szHTTPURL);
_tcscat(szHTTPURL, g_szISBN);
// Load the XML document
if (loadDocument(pXMLDoc, szHTTPURL, true))
{
// Add an attribute and an element
updateDocument(pXMLDoc);
// Save the updated document as a local XML file
pXMLDoc->save(g_szLocalFile);
}
else
{// Load Failed
printMSXMLError(pXMLDoc);
}
}
catch(...)
{// Exception handling
}
CoUninitialize();
return 0;
}
|
5. |
You‘ll notice that the main function simply calls some utility functions to load the XML document, update it and print an error if the document fails to load. These functions are declared and defined in a header file called Utils.h. Let‘s look at each function individually. |
6. |
Let‘s first look at a function that makes sure that MSXML 4.0 is installed:
bool isMSXMLInstalled()
{
try
{
HKEY hKey;
DWORD retCode;
retCode = RegOpenKeyEx(HKEY_CLASSES_ROOT,
_T("CLSID\\{88d969c0-f192-11d4-a65f-0040963251e5}\\InProcServer32"),
0,
KEY_QUERY_VALUE,
&hKey);
if (retCode != ERROR_SUCCESS) return false;
retCode = RegQueryValueEx(hKey, _T(""), NULL, NULL,
(LPBYTE)szTemp, &(dwLen = sizeof(szTemp)));
if (retCode != ERROR_SUCCESS) return false;
RegCloseKey(hKey);
double dVer;
int i;
for (i = _tcslen(szTemp); i >= 0; --i)
{
if (szTemp[i] == _T(‘\\‘))
break;
}
if (_stscanf(szTemp + i + 1, _T("msxml%lf"), &dVer) == 0 || dVer < 4.0)
{
_ftprintf(stderr, _T("\nError: MSXML 4.0 is not installed. Exiting.\n"));
return false;
}
else
{
return true;
}
}
catch(...)
{// Exception handling
}
return false;
}
|
7. |
The above function simply uses the MSXML 4.0 DOMDocument (Msxml2.DOMDocument.4.0) CLSID to search the corresponding COM DLL in the registry. If it is MSXML4.dll, the method returns true, else it returns false. |
8. |
The next function in the Utils.h is loadDocument. It creates MSXML DOMDocument instance using the version dependent ProgID and then loads the document. The method initializes the first parameter (pXMLDoc), and returns True or False based on if the document was successfully loaded or not.
_variant_t loadDocument(IXMLDOMDocument2Ptr& pXMLDoc, LPCTSTR szDocURL, bool bOverHTTP)
{
_variant_t varLoadResult((bool)FALSE);
try
{
// Create MSXML DOM object
EVAL_HR(pXMLDoc.CreateInstance("Msxml2.DOMDocument.4.0"));
// Load the document synchronously
pXMLDoc->async = false;
if (bOverHTTP)
{
// If loading the document over HTTP (see KB Q321125 for details)
pXMLDoc->setProperty("ServerHTTPRequest", VARIANT_TRUE);
}
// Load the XML document
varLoadResult = pXMLDoc->load(szDocURL);
}
catch(...)
{//Exception handling
}
return varLoadResult;
}
|
9. |
Once the XML document is loaded in the DOM tree, the following function is used to add an attribute to the root element, and update/add an element under the root element.
void updateDocument(IXMLDOMDocument2Ptr& pXMLDoc)
{
try
{
IXMLDOMNodePtr pLastSavedNode = NULL;
IXMLDOMElementPtr pRootElem = NULL;
// Get root element
EVAL_HR(pXMLDoc->get_documentElement(&pRootElem));
// Add the ISBN attribute to the root element
pRootElem->setAttribute("ISBN", g_szISBN);
// See KB Article Q313372 for details on
// default namespace and XPath expression evaluation
TCHAR szTemp[MAX_PATH] = "xmlns:defNS=‘";
// Get the default namespace on the root element
_bstr_t bstrNamespaceURI = pRootElem->namespaceURI;
_tcscat(szTemp, bstrNamespaceURI);
_tcscat(szTemp, "‘");
pXMLDoc->setProperty("SelectionNamespaces", szTemp);
// The XPath expression
_tcscpy(szTemp, "//defNS:");
_tcscat(szTemp, g_szNode);
// See if the "LastSaved" element exists
pLastSavedNode = pRootElem->selectSingleNode(_bstr_t(szTemp));
if(pLastSavedNode == NULL)
{// Element not found!
_variant_t varNodeType((short)MSXML2::NODE_ELEMENT);
// create the LastSaved node
pLastSavedNode = pXMLDoc->createNode(varNodeType, g_szNode, bstrNamespaceURI);
// append this new node under the document root element
pRootElem->appendChild(pLastSavedNode);
}
// Get current Date and Time
time_t timCurDate;
time (&timCurDate);
// And set it‘s value to current date and time
pLastSavedNode->nodeTypedValue = ctime (&timCurDate);
}
catch(...)
{//Exception Handling
}
}
|
10. |
The above method first gets the document‘s root element. It then adds/updates the ISBN attribute on the root node.
Then we use the XPath expression and selectSingleNode method to see if the node named LastSaved already exists as a child of the root element. If found, we just update its value, else we create a new node and attach it as a child to the root element.
When creating the new node (by calling createNode), we make sure to give the same namespace as the default namespace on the root element, so that the newly created node does not contain a blank namespace declaration, and in fact belongs to the document‘s default namespace. |
11. |
The final utility function, printMSXMLError, simply uses the IXMLDOMParseError interface to print some error information on the stderr stream:
void printMSXMLError(const IXMLDOMDocument2Ptr& pXMLDoc)
{
try
{
// Get parseError interface
IXMLDOMParseErrorPtr pError = NULL;
EVAL_HR(pXMLDoc->get_parseError(&pError));
_ftprintf(stderr, pError->reason);
}
catch(...)
{//Exception handling
}
}
|
12. |
The code uses some global variables defined in another header file named GlobalDefs.h:
LPCTSTR g_szHTTPURL =
_T("http://www.PerfectXML.net/WebServices/SalesRankNPrice/BookService.asmx/GetAll?ISBN=");
LPCTSTR g_szISBN = _T("0072223693");
// Uncomment following two lines in case not connected to the internet
//LPCTSTR g_szHTTPURL = _T("c:\\SalesRankNPrice.xml");
//LPCTSTR g_szISBN = _T("");
LPCTSTR g_szLocalFile = _T("c:\\SalesRankNPrice.xml");
LPCTSTR g_szNode = _T("LastSaved");
#define TEMP_SIZE _MAX_PATH // size of short buffer
static _TCHAR szTemp[TEMP_SIZE]; // multipurpose buffer on stack
static DWORD dwLen; // buffer size
|
|
Here is the text from the ReadMe.TXT file included with the code download for this sample application:
========================================================================
CONSOLE APPLICATION : MSXML4DOM
========================================================================
MSXML4DOM.cpp
Sample code to illustrate using MSXML 4.0 (SP1) basic DOM
(Document Object Model) features in C++.
This application creates
a.) loads an XML document from an HTTP location
(
actually, sends a HTTP GET request to a
Web service (SalesRankNPrice) method.
)
b.) Modifies that document
(
creates the element named LastSaved
under the root element, and sets its value
to current date and time.
Also adds the ISBN attribute to the root element
)
c.) Saves the updated document on the local hard disk
After the program finishes, open the C:\SalesRankNPrice.xml (g_szLocalFile)
file using Internet Explorer to see the results.
--------------------------------------------------------------
Copyright (C) 2002 http://www.PerfectXML.com
Created: July 10, 2002
Author: PerfectXML.com Team (msxml@PerfectXML.com)
See http://www.PerfectXML.com/CPPMSXML/20020710.asp for details.
/////////////////////////////////////////////////////////////////////////////
|
|
|