// DynamDOM.cpp : Defines the entry point for the console application. // #include #include #pragma warning(disable : 4127) // conditional expression is constant // Macro that calls a COM method returning HRESULT value. #define CHK_HR(stmt) do { hr=(stmt); if (FAILED(hr)) goto CleanUp; } while(0) // Macro to verify memory allcation. #define CHK_ALLOC(p) do { if (!(p)) { hr = E_OUTOFMEMORY; goto CleanUp; } } while(0) // Macro that releases a COM object if not NULL. #define SAFE_RELEASE(p) do { if ((p)) { (p)->Release(); (p) = NULL; } } while(0) // Helper function to create a VT_BSTR variant from a null terminated string. HRESULT VariantFromString(PCWSTR wszValue, VARIANT &Variant) { HRESULT hr = S_OK; BSTR bstr = SysAllocString(wszValue); CHK_ALLOC(bstr); V_VT(&Variant) = VT_BSTR; V_BSTR(&Variant) = bstr; CleanUp: return hr; } // Helper function to create a DOM instance. HRESULT CreateAndInitDOM(IXMLDOMDocument **ppDoc) { HRESULT hr = CoCreateInstance(__uuidof(DOMDocument60), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(ppDoc)); if (SUCCEEDED(hr)) { // these methods should not fail so don't inspect result (*ppDoc)->put_async(VARIANT_FALSE); (*ppDoc)->put_validateOnParse(VARIANT_FALSE); (*ppDoc)->put_resolveExternals(VARIANT_FALSE); (*ppDoc)->put_preserveWhiteSpace(VARIANT_TRUE); } return hr; } // Helper that allocates the BSTR param for the caller. HRESULT CreateElement(IXMLDOMDocument *pXMLDom, PCWSTR wszName, IXMLDOMElement **ppElement) { HRESULT hr = S_OK; *ppElement = NULL; BSTR bstrName = SysAllocString(wszName); CHK_ALLOC(bstrName); CHK_HR(pXMLDom->createElement(bstrName, ppElement)); CleanUp: SysFreeString(bstrName); return hr; } // Helper function to append a child to a parent node. HRESULT AppendChildToParent(IXMLDOMNode *pChild, IXMLDOMNode *pParent) { HRESULT hr = S_OK; IXMLDOMNode *pChildOut = NULL; CHK_HR(pParent->appendChild(pChild, &pChildOut)); CleanUp: SAFE_RELEASE(pChildOut); return hr; } // Helper function to create and add a processing instruction to a document node. HRESULT CreateAndAddPINode(IXMLDOMDocument *pDom, PCWSTR wszTarget, PCWSTR wszData) { HRESULT hr = S_OK; IXMLDOMProcessingInstruction *pPI = NULL; BSTR bstrTarget = SysAllocString(wszTarget); BSTR bstrData = SysAllocString(wszData); CHK_ALLOC(bstrTarget && bstrData); CHK_HR(pDom->createProcessingInstruction(bstrTarget, bstrData, &pPI)); CHK_HR(AppendChildToParent(pPI, pDom)); CleanUp: SAFE_RELEASE(pPI); SysFreeString(bstrTarget); SysFreeString(bstrData); return hr; } // Helper function to create and add a comment to a document node. HRESULT CreateAndAddCommentNode(IXMLDOMDocument *pDom, PCWSTR wszComment) { HRESULT hr = S_OK; IXMLDOMComment *pComment = NULL; BSTR bstrComment = SysAllocString(wszComment); CHK_ALLOC(bstrComment); CHK_HR(pDom->createComment(bstrComment, &pComment)); CHK_HR(AppendChildToParent(pComment, pDom)); CleanUp: SAFE_RELEASE(pComment); SysFreeString(bstrComment); return hr; } // Helper function to create and add an attribute to a parent node. HRESULT CreateAndAddAttributeNode(IXMLDOMDocument *pDom, PCWSTR wszName, PCWSTR wszValue, IXMLDOMElement *pParent) { HRESULT hr = S_OK; IXMLDOMAttribute *pAttribute = NULL; IXMLDOMAttribute *pAttributeOut = NULL; // Out param that is not used BSTR bstrName = NULL; VARIANT varValue; VariantInit(&varValue); bstrName = SysAllocString(wszName); CHK_ALLOC(bstrName); CHK_HR(VariantFromString(wszValue, varValue)); CHK_HR(pDom->createAttribute(bstrName, &pAttribute)); CHK_HR(pAttribute->put_value(varValue)); CHK_HR(pParent->setAttributeNode(pAttribute, &pAttributeOut)); CleanUp: SAFE_RELEASE(pAttribute); SAFE_RELEASE(pAttributeOut); SysFreeString(bstrName); VariantClear(&varValue); return hr; } // Helper function to create and append a text node to a parent node. HRESULT CreateAndAddTextNode(IXMLDOMDocument *pDom, PCWSTR wszText, IXMLDOMNode *pParent) { HRESULT hr = S_OK; IXMLDOMText *pText = NULL; BSTR bstrText = SysAllocString(wszText); CHK_ALLOC(bstrText); CHK_HR(pDom->createTextNode(bstrText, &pText)); CHK_HR(AppendChildToParent(pText, pParent)); CleanUp: SAFE_RELEASE(pText); SysFreeString(bstrText); return hr; } // Helper function to create and append a CDATA node to a parent node. HRESULT CreateAndAddCDATANode(IXMLDOMDocument *pDom, PCWSTR wszCDATA, IXMLDOMNode *pParent) { HRESULT hr = S_OK; IXMLDOMCDATASection *pCDATA = NULL; BSTR bstrCDATA = SysAllocString(wszCDATA); CHK_ALLOC(bstrCDATA); CHK_HR(pDom->createCDATASection(bstrCDATA, &pCDATA)); CHK_HR(AppendChildToParent(pCDATA, pParent)); CleanUp: SAFE_RELEASE(pCDATA); SysFreeString(bstrCDATA); return hr; } // Helper function to create and append an element node to a parent node, and pass the newly created // element node to caller if it wants. HRESULT CreateAndAddElementNode(IXMLDOMDocument *pDom, PCWSTR wszName, PCWSTR wszNewline, IXMLDOMNode *pParent, IXMLDOMElement **ppElement = NULL) { HRESULT hr = S_OK; IXMLDOMElement* pElement = NULL; CHK_HR(CreateElement(pDom, wszName, &pElement)); // Add NEWLINE+TAB for identation before this element. CHK_HR(CreateAndAddTextNode(pDom, wszNewline, pParent)); // Append this element to parent. CHK_HR(AppendChildToParent(pElement, pParent)); CleanUp: if (ppElement) *ppElement = pElement; // Caller is repsonsible to release this element. else SAFE_RELEASE(pElement); // Caller is not interested on this element, so release it. return hr; } void dynamDOM() { HRESULT hr = S_OK; IXMLDOMDocument *pXMLDom = NULL; IXMLDOMElement *pRoot = NULL; IXMLDOMElement *pNode = NULL; IXMLDOMElement *pSubNode = NULL; IXMLDOMDocumentFragment *pDF = NULL; BSTR bstrXML = NULL; VARIANT varFileName; VariantInit(&varFileName); CHK_HR(CreateAndInitDOM(&pXMLDom)); // Create a processing instruction element. CHK_HR(CreateAndAddPINode(pXMLDom, L"xml", L"version='1.0'")); // Create a comment element. CHK_HR(CreateAndAddCommentNode(pXMLDom, L"sample xml file created using XML DOM object.")); // Create the root element. CHK_HR(CreateElement(pXMLDom, L"root", &pRoot)); // Create an attribute for the element, with name "created" and value "using dom". CHK_HR(CreateAndAddAttributeNode(pXMLDom, L"created", L"using dom", pRoot)); // Next, we will create and add three nodes to the element. // Create a to hold text content. CHK_HR(CreateAndAddElementNode(pXMLDom, L"node1", L"\n\t", pRoot, &pNode)); CHK_HR(CreateAndAddTextNode(pXMLDom, L"some character data", pNode)); SAFE_RELEASE(pNode); // Create a to hold a CDATA section. CHK_HR(CreateAndAddElementNode(pXMLDom, L"node2", L"\n\t", pRoot, &pNode)); CHK_HR(CreateAndAddCDATANode(pXMLDom, L"", pNode)); SAFE_RELEASE(pNode); // Create to hold a doc fragment with three sub-elements. CHK_HR(CreateAndAddElementNode(pXMLDom, L"node3", L"\n\t", pRoot, &pNode)); // Create a document fragment to hold three sub-elements. CHK_HR(pXMLDom->createDocumentFragment(&pDF)); // Create 3 subnodes. CHK_HR(CreateAndAddElementNode(pXMLDom, L"subNode1", L"\n\t\t", pDF)); CHK_HR(CreateAndAddElementNode(pXMLDom, L"subNode2", L"\n\t\t", pDF)); CHK_HR(CreateAndAddElementNode(pXMLDom, L"subNode3", L"\n\t\t", pDF)); CHK_HR(CreateAndAddTextNode(pXMLDom, L"\n\t", pDF)); // Append pDF to . CHK_HR(AppendChildToParent(pDF, pNode)); SAFE_RELEASE(pNode); // Add NEWLINE for identation before . CHK_HR(CreateAndAddTextNode(pXMLDom, L"\n", pRoot)); // add to document CHK_HR(AppendChildToParent(pRoot, pXMLDom)); CHK_HR(pXMLDom->get_xml(&bstrXML)); wprintf(L"Dynamically created DOM:\n%s\n", bstrXML); CHK_HR(VariantFromString(L"dynamDOM.xml", varFileName)); CHK_HR(pXMLDom->save(varFileName)); wprintf(L"DOM saved to dynamDOM.xml\n"); CleanUp: SAFE_RELEASE(pXMLDom); SAFE_RELEASE(pRoot); SAFE_RELEASE(pNode); SAFE_RELEASE(pDF); SAFE_RELEASE(pSubNode); SysFreeString(bstrXML); VariantClear(&varFileName); } int __cdecl wmain() { HRESULT hr = CoInitialize(NULL); if (SUCCEEDED(hr)) { dynamDOM(); CoUninitialize(); } return 0; }