Source: validateDOM.cpp
The source code performs the following basic steps:
- Creates a DOM instance (
pXMLDoc
) to hold the XML data. - Creates a DOM instance (
pXSDDoc
) to hold the XML Schema definition. - Creates an
IXMLSchemaCollection
orIXMLSchemaCollection2
object (pSCache
). This object is also called a schema cache. The application then adds the XML Schema definition (pXSDDoc
) to thepSCache
. - Associates
pSCache
with theschemas
property of the DOM object for the XML data (pXMLDoc
). - Calls the following validation methods on the DOM object for XML data (
pXMLDoc
):- Calls the
ValidateDocument
function. This function then calls thevalidate
method onpXMLDoc
to validate the data set as a whole.and/or
- Calls the
ValidateDocumentNodes
function. This function then calls thevalidateNode(pNode)
method onpXMLDoc
to validate a node object (pNode
) selected frompXMLDoc
.
- Calls the
Checks the error returned from validate
method and/or the validateNode(pNode)
method, to determine if the specified XML data set is valid against the given XML Schema definition.
C/C++ Source File (validateDOM.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 put 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: IXMLDOMDocument3 * DomFromCOM() { HRESULT hr; IXMLDOMDocument3 *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"); HRCALL( pxmldoc->put_preserveWhiteSpace(VARIANT_TRUE), "should never fail"); return pxmldoc; clean: if (pxmldoc) { pxmldoc->Release(); } return NULL; } // Helper function packaging a BSTR into a variant: VARIANT VariantString(BSTR str) { VARIANT var; VariantInit(&var); V_BSTR(&var) = SysAllocString(str); V_VT(&var) = VT_BSTR; return var; } // Helper function packaging an object into a variant: VARIANT VariantObject(IUnknown *pUnk) { VARIANT var; HRESULT hr; IDispatch *pDisp=NULL; VariantInit(&var); HRCALL(pUnk->QueryInterface(IID_IDispatch,(void**)&pDisp),""); var.pdispVal = pDisp; var.vt = VT_DISPATCH; return var; clean: VariantClear(&var); return var; } // Helper function to display parse error: void ReportParseError(IXMLDOMDocument *pDom, char *desc) { IXMLDOMParseError *pXMLErr=NULL; BSTR bstrReason = NULL; HRESULT hr; HRCALL(pDom->get_parseError(&pXMLErr), "dom->get_parseError: "); HRCALL(pXMLErr->get_reason(&bstrReason), "parseError->get_reason: "); dprintf("%s %S\n",desc, bstrReason); clean: if (pXMLErr) pXMLErr->Release(); if (bstrReason) SysFreeString(bstrReason); } // Validate XML document as a whole. void ValidateDocument(IXMLDOMDocument2 *pDom) { IXMLDOMParseError *pErr=NULL; BSTR bstr = NULL; HRESULT hr; long eCode; if (!pDom) { dprintf("Can't validate document. Invalid DOM\n"); return; } dprintf("Validating DOM...\n"); HRCALL(pDom->validate(&pErr), ""); HRCALL(pErr->get_errorCode(&eCode), ""); if (eCode != 0) { HRCALL(pErr->get_reason(&bstr), ""); dprintf("\tXMLDoc is not valid because\n%S\n",bstr); SysFreeString(bstr); bstr = NULL; } else { HRCALL(pDom->get_xml(&bstr),""); dprintf("\tXMLDoc is validated: \n%S\n",bstr); SysFreeString(bstr); bstr = NULL; } clean: if (pErr) pErr->Release(); if (bstr) SysFreeString(bstr); } // Validate Document nodes, node by node. void ValidateDocumentNodes(IXMLDOMDocument3 *pDom, BSTR xpath) { IXMLDOMNode * pNode = NULL; IXMLDOMNodeList *pNodelist = NULL; IXMLDOMParseError *pError = NULL; BSTR bstr = NULL; long length, eCode, i; HRESULT hr; if (!pDom) { dprintf("Can't validate document nodes. Invalid DOM\n"); return; } HRCALL(pDom->selectNodes(xpath,&pNodelist),""); HRCALL(pNodelist->get_length(&length), ""); for (i=0; i<length; i++) { HRCALL(pNodelist->get_item(i, &pNode), ""); HRCALL(pDom->validateNode(pNode, &pError),""); HRCALL(pError->get_errorCode(&eCode), ""); HRCALL(pNode->get_nodeName(&bstr), ""); if (eCode != 0 ) { BSTR bstr1 = NULL; HRCALL(pError->get_reason(&bstr1), ""); dprintf("\t<%S> (%d) is not valid because\n%S\n", bstr, i, bstr1); SysFreeString(bstr1); bstr1=NULL; } else { dprintf("\t<%S> (%d) is a valid node\n",bstr,i); } SysFreeString(bstr); bstr=NULL; } clean: if (bstr) SysFreeString(bstr); if (pError) pError->Release(); if (pNode) pNode->Release(); if (pNodelist) pNodelist->Release(); return; } int main(int argc, char* argv[]) { IXMLDOMDocument3 *pXMLDoc = NULL; IXMLDOMDocument3 *pXSDDoc = NULL; IXMLDOMSchemaCollection *pSCache = NULL; BSTR bstr = NULL; VARIANT_BOOL status; VARIANT var; HRESULT hr; CoInitialize(NULL); VariantInit(&var); // Create a DOm and load a document from books.xml pXMLDoc = DomFromCOM(); if (!pXMLDoc) goto clean; VariantClear(&var); var = VariantString(L"books.xml"); HRCALL(pXMLDoc->load(var, &status), ""); if (status!=VARIANT_TRUE) { ReportParseError(pXMLDoc, "Failed to load DOM from books.xml"); goto clean; } // Create a Dom and load a schema from books.xsd. pXSDDoc = DomFromCOM(); if (!pXSDDoc) goto clean; VariantClear(&var); var = VariantString(L"books.xsd"); HRCALL(pXSDDoc->load(var, &status), ""); if (status!=VARIANT_TRUE) { ReportParseError(pXSDDoc, "Failed to load DOM from books.xsd"); goto clean; } // Create a schema collection object. HRCALL( CoCreateInstance(__uuidof(XMLSchemaCache50), NULL, CLSCTX_INPROC_SERVER, __uuidof(IXMLDOMSchemaCollection), (void**)&pSCache), "Create a new Schema collection object"); // Add schema to the schema collection. bstr = SysAllocString(L"urn:books"); VariantClear(&var); var = VariantObject(pXSDDoc); HRCALL(pSCache->add(bstr,var), "add schema"); SysFreeString(bstr); bstr = NULL; VariantClear(&var); // Attaching the schema to the XML document. var = VariantObject(pSCache); HRCALL(pXMLDoc->putref_schemas(var),""); VariantClear(&var); // Validate the document as a whole. ValidateDocument(pXMLDoc); // Validate all //book nodes, node by node. bstr = SysAllocString(L"//book"); ValidateDocumentNodes(pXMLDoc, bstr); SysFreeString(bstr); bstr = NULL; // Validate all //book/* nodes, node by node. bstr = SysAllocString(L"//book/*"); ValidateDocumentNodes(pXMLDoc, bstr); SysFreeString(bstr); bstr = NULL; clean: if (bstr) SysFreeString(bstr); if (&var) VariantClear(&var); if (pXMLDoc) pXMLDoc->Release(); if (pXSDDoc) pXSDDoc->Release(); if (pSCache) pSCache->Release(); CoUninitialize(); return 0; }
To add validateDOM.cpp to the project
- 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 validateDOM.cpp.
- 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 validateDOM project.