Source: XSLT.cpp

MSXML 5.0 SDK

Microsoft XML Core Services (MSXML) 5.0 for Microsoft Office - DOM Developer's Guide

Source: XSLT.cpp

The source code listed below demonstrates how to call the transformNode method and the transformNodeToObject method in a C/C++ program. Specifically, the code performs the following steps:

  1. Loads the XML data file (stocks.xml) into an XML DOM object (pXMLDom).
  2. Loads the XSLT style sheet (stocks.xsl) into an XML DOM object (pXSLDoc).
  3. Calls the transformNode(pXSLDoc) method on pXMLDom to do the transformation, holds the result in a string, and prints the output to the console.
  4. Creates an XML DOM object (pXMLOut) to hold the output of the transformNodeToObject method.
  5. Calls the transformNodeToObject method on pXMLDom to do the transformation; holds the resulting object in pXMLOut; prints out the XML result; and serializes the output object in an HTML file, stocks.htm.

C/C++ Source File (XSLT.cpp)

#include <stdio.h>
#include <windows.h>
#import <msxml5.dll> raw_interfaces_only
using namespace MSXML2;

// Macro that calls a COM method returning HRESULT value:
#define HRCALL(a, errmsg) \
do { \
    hr = (a); \
    if (FAILED(hr)) { \
        dprintf( "%s:%d  HRCALL Failed: %s\n  0x%.8x = %s\n", \
                __FILE__, __LINE__, errmsg, hr, #a ); \
        goto clean; \
    } \
} while (0)

// Helper function that puts output in stdout and debug window
// in Visual Studio:
void dprintf( char * format, ...)
{
    static char buf[1024];
    va_list args;
    va_start( args, format );
    vsprintf( buf, format, args );
    va_end( args);
    OutputDebugStringA( buf);
    printf("%s", buf);
}

// Helper function to create a DOM instance: 
IXMLDOMDocument * DomFromCOM()
{
   HRESULT hr;
   IXMLDOMDocument *pxmldoc = NULL;

    HRCALL( CoCreateInstance(__uuidof(DOMDocument50),
                      NULL,
                      CLSCTX_INPROC_SERVER,
                      __uuidof(IXMLDOMDocument),
                      (void**)&pxmldoc),
            "Create a new DOMDocument");

    HRCALL( pxmldoc->put_async(VARIANT_FALSE),
            "should never fail");
    HRCALL( pxmldoc->put_validateOnParse(VARIANT_FALSE),
            "should never fail");
    HRCALL( pxmldoc->put_resolveExternals(VARIANT_FALSE),
            "should never fail");

   return pxmldoc;
clean:
   if (pxmldoc)
    {
      pxmldoc->Release();
    }
   return NULL;
}


int main(int argc, char* argv[])
{
   IXMLDOMDocument *pXMLDom=NULL;
   IXMLDOMDocument *pXSLDoc=NULL;
   IXMLDOMParseError *pXMLErr=NULL;
   IXMLDOMDocument *pXMLOut = NULL;
   IDispatch *pDisp=NULL;
   BSTR bstr = NULL;
   long ecode;
   VARIANT_BOOL status;
   VARIANT var;
   HRESULT hr;

   CoInitialize(NULL);

   pXMLDom = DomFromCOM();
   if (!pXMLDom) goto clean;

   VariantInit(&var);
   V_BSTR(&var) = SysAllocString(L"stocks.xml");
   V_VT(&var) = VT_BSTR;
   HRCALL(pXMLDom->load(var,&status),"dom->load(): ");

   if (status!=VARIANT_TRUE) {
      HRCALL(pXMLDom->get_parseError(&pXMLErr),
               "dom->get_parseError: ");
      HRCALL(pXMLErr->get_reason(&bstr),
               "parseError->get_reason: ");
      dprintf("Failed to load DOM from stocks.xml. %S\n",
               bstr);
      goto clean;
   }
   
   pXSLDoc = DomFromCOM();
   if (!pXSLDoc) goto clean;

   VariantClear(&var);
   V_BSTR(&var) = SysAllocString(L"stocks.xsl");
   V_VT(&var) = VT_BSTR;
   HRCALL(pXSLDoc->load(var,&status), "xsl->load(): ");
   if (status != VARIANT_TRUE) {
      HRCALL(pXMLDom->get_parseError(&pXMLErr),
               "dom->get_parseError: ");
      HRCALL(pXMLErr->get_reason(&bstr),
               "parseError->get_reason: ");
      dprintf("Failed to load DOM from stocks.xsl. %S\n",
               bstr);
      goto clean;
   }

   // Transform dom to a string:
   HRCALL(pXMLDom->transformNode(pXSLDoc, &bstr),"");
   HRCALL(pXMLDom->get_parseError(&pXMLErr), "");
   HRCALL(pXMLErr->get_errorCode(&ecode), "");
   if (ecode != 0) {
      if (bstr) SysFreeString(bstr);
      HRCALL(pXMLErr->get_reason(&bstr),"");
      dprintf("Failed to transformNode:\n%S\n", bstr);
      goto clean;
   }
   dprintf("output from transformNode:\n%S\n",bstr);

   // Transform dom to another dom object:
   pXMLOut = DomFromCOM();
   if (!pXMLOut) goto clean;

   HRCALL(pXMLOut->QueryInterface(IID_IDispatch,(void**)&pDisp),
         "QI(IDispatch): ");
   VariantClear(&var);
   var.vt = VT_DISPATCH;
   var.pdispVal = pDisp;

   HRCALL(pXMLDom->transformNodeToObject(pXSLDoc, var),
         "tramsformNodeToObject: ");

   if (bstr) SysFreeString(bstr);
   HRCALL(pXMLOut->get_xml(&bstr), "");
    dprintf("output from transformNodeToObject:\n%S\n",bstr);
   
   VariantClear(&var);
   pDisp=NULL;
   V_VT(&var) = VT_BSTR;
   V_BSTR(&var) = SysAllocString(L"stocks.htm");
   HRCALL(pXMLOut->save(var), "XMLOut->save: ");

   dprintf("The above output is also saved in stocks.htm.\n");

clean:
   if (bstr) SysFreeString(bstr);
   if (&var) VariantClear(&var);
   if (pXMLErr) {  pXMLErr->Release();}
   if (pXMLDom) {  pXMLDom->Release();}
   if (pXMLOut) {  pXMLOut->Release();}
   if (pXSLDoc) {  pXSLDoc->Release();}

   CoUninitialize();
   return 0;
}

To add XSLT.cpp to the project

  1. Create a new C++ source file. For detailed instructions on how to do this, see Set Up My Visual C++ Project. Name the new file XSLT.cpp.
  2. Copy the C/C++ source code above and paste it into the source file you just created.

Next, we'll add the resource files to the XSLT project.