![](//pubimage.360doc.com/wz/default.gif) 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. ///////////////////////////////////////////////////////////////////////////// | |