- Platforms and License
- Technologies Supported
- Where to Obtain It
- Reusable Design and Code: DOM Walkers
- Implementing DOMWalkerWizard
- About This Article
Implementing DOMWalkerWizard
Visual Studio provides the ability to create applications by using wizards, which are step-by-step dialogs that help create the skeleton of an application by means of simple user input. The following sub-sections show how to implement a wizard for creating generic DOM Walkers.
A custom application wizard is composed of three things:
Visual interface: The dialogs in which the user makes selections
Templates: The actual templates for the files on the generated project
Configuration files: They instruct Visual Studio about the template files, and how they should be mapped to the generated project.
The implementation of DOMWalkerWizard is inspected in terms of these three components in the following sub-sections. After this, you will be able to extend this wizard to fit your needs better and even create your own.
Visual Interface: The Custom Dialogs
There are two dialog classes in the DOMWalkerWizard project. They implement a simple GUI for the user to enter her preferences about traversal, helper generation, and node types. Figure 3 shows both dialogs.
Figure 3 The DOMWalkerWizard GUI
In order to remember the preferences of the user, the values represented by the widgets are entered in a dictionary. This is done in the function OnDismiss() as shown in Listing 5.
Listing 5: OnDismiss() Function for DOMWalkerWizard
BOOL CCustom2Dlg::OnDismiss() { if (!UpdateData(TRUE)) return FALSE; if(m_elements) DOMWalkerWizardaw.m_Dictionary["WANT_ELEMENTS"] = "YES"; else DOMWalkerWizardaw.m_Dictionary["WANT_ELEMENTS"] = ""; if(m_text) DOMWalkerWizardaw.m_Dictionary["WANT_TEXT"] = "YES"; else DOMWalkerWizardaw.m_Dictionary["WANT_TEXT"] = ""; if(m_pis) DOMWalkerWizardaw.m_Dictionary["WANT_PIS"] = "YES"; else DOMWalkerWizardaw.m_Dictionary["WANT_PIS"] = ""; return TRUE; // return FALSE if the dialog shouldn't be dismissed }
Templates
The main part of the wizard is the templates. The templates are processed according to the values set in the dictionary, creating the files in the generated project. For our case, we define two templates (see Listings 6 and 7), one for the interface and one for the implementation of our walker class.
Listing 6: DOMWalker.h
// The variable root is automatically set to the name of the project #ifndef $$root$$XMLWALKER_H #define $$root$$XMLWALKER_H #include <windows.h> #import "msxml3.dll" using namespace MSXML2; class $$root$$Walker { public: /** recursive method used to navigate the tree */ void visit(IXMLDOMNodePtr n); $$IF(WANT_HELPER) //****************************************************************************** // Internal Helper Class //****************************************************************************** class Helper { public: static IXMLDOMNodePtr readXMLFile(const char *name); }; $$ENDIF }; #endifListing 7: DOMWalker.cpp
#include "$$root$$Walker.h" void $$root$$Walker::visit(IXMLDOMNodePtr n) { $$IF(INORDER) // INORDER: visit the left child, then the rest if(n->childNodes->length > 0) visit(n->childNodes->item[0]); $$ENDIF $$IF(POSTORDER) // POSTORDER: visit the children, then the current node for(int i = 0; i < n->childNodes->length ;i++) visit(n->childNodes->item[i]); $$ENDIF $$IF(PREORDER) // PREORDER: visit this node, then visit its left child, then the rest // Treat the node here first $$ENDIF $$IF(WANT_ELEMENTS) if(n->nodeType == NODE_ELEMENT) { // handle the element here // At this point you may want to look for the name of the // element with: // if(!strcmp(n->nodeName,"foo")) // { // and perhaps get an attribute with: // IXMLDOMNodePtr att; // n->attributes->get_item(0,&att); // (these are not the only mechanisms) // } } $$ENDIF $$IF(WANT_TEXT) if(n->nodeType == NODE_TEXT) { // hanlde the text here } $$ENDIF $$IF(WANT_PIS) if(n->nodeType == NODE_PROCESSING_INSTRUCTION) { // hanlde the P.I. here } // The Source for the wizard itself is included with the // Book's CDROM, so you can enhance this file with other cases // for other node types. $$ENDIF $$IF(INORDER) // we already visited the first child for(int i = 1; i < n->childNodes->length ;i++) visit(n->childNodes->item[i]); $$ENDIF $$IF(PREORDER) // go through the rest of children for(int i = 0; i < n->childNodes->length ;i++) visit(n->childNodes->item[i]); $$ENDIF } $$IF(WANT_HELPER) IXMLDOMNodePtr $$root$$Walker::Helper::readXMLFile(const char *name) { try { IXMLDOMDocumentPtr docPtr; // Init docPtr.CreateInstance("msxml2.domdocument"); // load a document _variant_t varXml(name); _variant_t varOut((bool)TRUE); varOut = docPtr->load(varXml); if ((bool)varOut == FALSE) throw(0); return docPtr; } catch(...) { // ... log, show a window, rethrow, whatever you prefer. return NULL; } } $$ENDIF
Configuration Files
The configuration files for the project simply record the message that is shown to the user once the process is completed and the association between templates and the names of the files in the generated project. Listing 8 shows only the file association. You can see message file either in the templates directory or simply by running the Wizard.
Listing 8: newproj.inf for DOMWalkerWizard
$$// newproj.inf = template for list of template files walker.cpp $$root$$Walker.cpp walker.h $$root$$Walker.hFinal Result
The final result of compiling our project is a wizard file (extension awx) that is placed under %MSDEVDIR%\TEMPLATES. Now, you can generate a DOMWalker by simply hitting New->Project and clicking on the DOMWalkerWizard, as you would do with any other application type in Visual Studio.
Figure 4 shows a project generated with our tool, including a correct preorder DOMWalker for elements and text and a helper class to read the DOM from disk.
Figure 4 Project Generated with DOMWalkerWizard
Toolkits/Frameworks Updates
C++ XML is a rapidly evolving field. For daily information on Xerces, MSXML, libmxml, and other Toolkits, please refer to the book's Web site.