分类: C/C++
2009-10-29 14:25:26
Tom Archer - MSFT () April 4, 2001 |
.
The key to understanding how to use the DOM is realizing that the DOM exposes (through its COM interface) XML documents as a hierarchical tree of nodes. As an example, take a look at the following sample XML document.
The DOM would interpret this document as follows:2000 Convertible 60,000 420 18.5 test model 30,000 350 15.5
::AfxOleInit
in the application class' InitInstance
function. Assuming you named your project the same as mine, your code should now look like this (with the AfOleInit call highlighted here):BOOL CXMLDOMFromVCApp::InitInstance() { AfxEnableControlContainer(); // .. other code ::AfxOleInit(); // Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application's message pump. return FALSE; }
#endif
directive.#importnamed_guids using namespace MSXML;
IXMLDOMDocumentPtr
is the pointer to the XML document itself and the IXMLDOMElement
is a pointer to the XML document root (as explained above).IXMLDOMDocumentPtr m_plDomDocument; IXMLDOMElementPtr m_pDocRoot;
OnInitDialog
member function (just before the return
statement). This code simply initializes the COM runtime and sets up your XML document smart pointer (m_plDomDocument
).// Initialize COM ::CoInitialize(NULL); HRESULT hr = m_plDomDocument.CreateInstance(CLSID_DOMDocument); if (FAILED(hr)) { _com_error er(hr); AfxMessageBox(er.ErrorMessage()); EndDialog(1); }
OnInitDialog
member function.// specify xml file name CString strFileName ("XMLDOMFromVC.xml"); // convert xml file name string to something COM can handle (BSTR) _bstr_t bstrFileName; bstrFileName = strFileName.AllocSysString(); // call the IXMLDOMDocumentPtr's load function to load the XML document variant_t vResult; vResult = m_plDomDocument->load(bstrFileName); if (((bool)vResult) == TRUE) // success! { // now that the document is loaded, we need to initialize the root pointer m_pDocRoot = m_plDomDocument->documentElement; AfxMessageBox("Document loaded successfully!"); } else { AfxMessageBox("Document FAILED to load!"); }Don't believe it's that easy? Add the following call to have the contents of your entire XML document displayed in a message box.
AfxMessageBox(m_plDomDocument->xml);Now, build and run the application and you should see results similar to Figure 1.
Loading and displaying an XML document can be done from Visual C++ with just a few lines of code using the DOM.
IXMLDOMNodePtr::firstChild
and IXMLDOMNodePtr::nextSibling
.The following reentrant function shows a way by which you can do this quite easily. In fact, if you insert this code into the dialog's OK button handler it will display each element in your document:
void CXMLDOMFromVCDlg::OnOK() { // send the root to the DisplayChildren function DisplayChildren(m_pDocRoot); } void CXMLDOMFromVCDlg::DisplayChildren(IXMLDOMNodePtr pParent) { // display the current node's name DisplayChild(pParent); // simple for loop to get all children for (IXMLDOMNodePtr pChild = pParent->firstChild; NULL != pChild; pChild = pChild->nextSibling) { // for each child, call this function so that we get // its children as well DisplayChildren(pChild); } } void CXMLDOMFromVCDlg::DisplayChild(IXMLDOMNodePtr pChild) { AfxMessageBox(pChild->nodeName); }If you were to build and run the project at this point, you would definitely notice something peculiar. The first few message boxes will appear as you might expect. The first one displaying the value "autos", followed by by "manufacturerer" and then "make" and finally "model". However, at that point (after the message box displaying the value "Model") things will get a little strange. Instead of a message box displaying the value "price", the value "#text" will be displayed! The reason for this is simple.
Let's look at an excerpt from the XML document:
...As you can see in the highlighted line above, a value succeeds the model tag, These "values" are still treated as nodes in XML when using the... 2000 Convertible 60,000 420 18.5
IXMLDOMNodePtr::firstChild
andIXMLDOMNodePtr::nextSibling
methods. Therefore, how do you know what type of node you have?By using the IXMLDOMNodePtr::nodeType
property. Simply modify your dialog's CXMLDOMFromVCDlg::DisplayChild
member function based on the highlighted portions below. When you've done that and run the code, you will see the expected values instead of the literal "#text".
void CXMLDOMFromVCDlg::DisplayChild(IXMLDOMNodePtr pChild) { if (class="codeHighlight">NODE_TEXT == pChild->nodeType) { AfxMessageBox(pChild->text); } else { AfxMessageBox(pChild->nodeName); } }You no doubt also noted the "magic" constant used above (NODE_TEXT). All the node types are defined with an
enum
in the msxml.tlh file that was generated with the #import
directive you used earlier. This enum structure is listed below:enum tagDOMNodeType
{
NODE_INVALID = 0,
NODE_ELEMENT = 1,
NODE_ATTRIBUTE = 2,
NODE_TEXT = 3,
NODE_CDATA_SECTION = 4,
NODE_ENTITY_REFERENCE = 5,
NODE_ENTITY = 6,
NODE_PROCESSING_INSTRUCTION = 7,
NODE_COMMENT = 8,
NODE_DOCUMENT = 9,
NODE_DOCUMENT_TYPE = 10,
NODE_DOCUMENT_FRAGMENT = 11,
NODE_NOTATION = 12
};
About the Author
I am a Program Manager and Content Strategist for the Microsoft MSDN Online team managing the Windows Vista and Visual C++ developer centers. Before being employed at Microsoft, I was awarded MVP status for the Visual C++ product. A 20+ year veteran of programming with various languages - C++, C, Assembler, RPG III/400, PL/I, etc. - I've also written many technical books (Inside C#, Extending MFC Applications with the .NET Framework, Visual C++.NET Bible, etc.) and 100+ online articles.