Click here to Skip to main content
11,496,146 members (635 online)
Click here to Skip to main content

How to load a tree view with a large XML file

, 7 Jun 2000 244.5K 3.1K 85
This article show you how to display very large XML in a tree view, and also shows you how to incorporate the MS XML parser in your app.
The site is currently in read-only mode for maintenance. Posting of new items will be available again shortly.
  • Download demo project - 50 Kb
  • Sample Image

    Introduction

    Recently I was required to display a very large XML file in a tree view, I tried to implement like "virtual list view" which displays whatever is visible in a view (when the user scrolls). After brainstorm and some web surfing I remembered windows explorer. I'm not sure how they implement it exactly but I guess they do same method as mine which expand any tree node on the fly i.e. don't populate the whole tree at start-up. If you don't do this, populate the whole tree for a 10 MB XML file size takes up to 45 minutes on a fast machine! doing my way will takes only approximately 3-5 seconds! The trick really is how to find out the relationship and info of any tree node and associated DOM node any where any time. To incorporate this into your app, either derive your class from CXmlTreeView or add appropriate message handlers and all helper methods to your own class.

    Note:

    • It'd be easier if you know how to incorporate XML parser into your app (this article uses Microsoft XML parser because of its available!), however, it's not a requirement.
    • You can apply the same method to any application-specific value instead of DOM node to populate a tree control
    • You can easily change this class to use as a tree control instead.

    The first you need to add a notify message handler for TVN_ITEMEXPANDING which notifies a tree view control's parent window that a parent item's list of child items is about to expand or collapse.

    void CXmlTreeView::OnItemexpanding(NMHDR*  pNMHDR, LRESULT* pResult) 
    {
        NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
        HTREEITEM hItem = pNMTreeView->itemNew.hItem;
        MSXML::IXMLDOMElement* node = (MSXML::IXMLDOMElement*)GetTreeCtrl().GetItemData(hItem);
        HRESULT hr;
      
        *pResult = 0;
     
        // If m_bOptimizeMemory is false then we optimize by not adding and deleting 
        // already added items. The trade-off is memory exhausted!
      
        CWaitCursor waitCursor;     // This could take a while!
        GetTreeCtrl().LockWindowUpdate();
        if (pNMTreeView->action == TVE_EXPAND) 
        {
            if (m_bOptimizeMemory == FALSE) 
            {
                HTREEITEM hChildItem;
                if ((hChildItem = GetTreeCtrl().GetChildItem(hItem)) != NULL) 
                {
                   MSXML::IXMLDOMElement* childNode = 
                              (MSXML::IXMLDOMElement*) GetTreeCtrl().GetItemData(hChildItem);
                     
                   if (childNode == NULL)
                   {
                      GetTreeCtrl().DeleteItem(hChildItem);
                      MSXML::IXMLDOMNode* firstChild = NULL;
                      hr = node->get_firstChild(&firstChild);
                      if (SUCCEEDED(hr) && firstChild != NULL)
                      {
                          if (populateNode((MSXML::IXMLDOMElement*)firstChild, hItem) == FALSE) 
                          {
                              *pResult = 1; 
                          }                
                      }
                   }
                }
             } 
             else
             {
                 deleteFirstChild(hItem);
                 MSXML::IXMLDOMNode* firstChild = NULL;
                 hr = node->get_firstChild(&firstChild);
                 if (SUCCEEDED(hr) && firstChild != NULL) 
                 {
                     if (populateNode((MSXML::IXMLDOMElement*)firstChild, hItem) == FALSE) 
                     {
                         *pResult = 1; 
                     }
                 }
              }
          }
          else
          {
              // pNMTreeView->action == TVE_COLLAPSE
              if (m_bOptimizeMemory == TRUE) 
              {
                  deleteAllChildren(hItem);
                  // Set button state.
                  if (node->hasChildNodes()) 
                  {
                       int nImage, nSelectedImage;
                       nImage = nSelectedImage = getIconIndex(node);
                       HTREEITEM hChildItem = GetTreeCtrl().InsertItem(_T(""), nImage, 
                           nSelectedImage, hItem);
                       GetTreeCtrl().SetItemData(hChildItem, (DWORD)NULL);
                  }
              }
          }
          GetTreeCtrl().UnlockWindowUpdate();
      }
      

    The key in this function is the calls to GetItemData(..) and populateNode(..).

    • GetItemData(..) will retrieve the DOM node value associated with the specified item so we can use this DOM node to figure out the relationship with the rest.
    • populateNode(..) will only populate all siblings of the [in] node which is the child node of the current node.
    • m_bOptimizeMemory is used to optimize memory by delete all children when collapse or not. This value is set to false by default when you can loadXML(..).
    // This function populates all siblings of the
      [in] node.
      //
      BOOL CXmlTreeView::populateNode(MSXML::IXMLDOMElement *node, const HTREEITEM &hParent)
      {
          HRESULT hr = S_OK;
          BSTR nodeType, nodeName;
          HTREEITEM hItem;
      
          node->get_nodeTypeString(&nodeType);
          if (!wcscmp(nodeType, L"element")) {
              node->get_nodeName(&nodeName);
              hItem = insertItem(node, CString(nodeName), ILI_ELEMENT, ILI_ELEMENT, hParent);
              populateAttributes(node, hItem);
          } else if(!wcscmp(nodeType, L"text")) {
              node->get_text(&nodeName);
              hItem = insertItem(node, CString(nodeName), ILI_TEXT, ILI_TEXT, hParent); 
          } else if(!wcscmp(nodeType, L"comment")) {
              node->get_nodeName(&nodeName);
              hItem = insertItem(node, CString(nodeName), ILI_COMMENT, ILI_COMMENT, hParent); 
          } else {    // Handle more data types here if needed.
              node->get_nodeName(&nodeName);
              hItem = insertItem(node, CString(nodeName), ILI_OTHER, ILI_OTHER, hParent); 
          }
      
          MSXML::IXMLDOMNode* nextSibling = NULL;
          hr = node->get_nextSibling(&nextSibling);
          if (SUCCEEDED(hr) && nextSibling != NULL) {
              populateNode((MSXML::IXMLDOMElement*)nextSibling, hParent);
          }
      
          return TRUE;
      }
      

    The key in this function is the call to helper function insertItem(..) which set DOM node value associated with the specified tree item.

    HTREEITEM CXmlTreeView::insertItem(MSXML::IXMLDOMElement *node, 
          const CString &nodeName, int nImage, int nSelectedImage, 
          HTREEITEM hParent /*= TVI_ROOT*/, HTREEITEM hInsertAfter /*= TVI_LAST*/)
      {
          HTREEITEM hItem = GetTreeCtrl().InsertItem(nodeName, nImage, 
              nSelectedImage, hParent, hInsertAfter); 
          GetTreeCtrl().SetItemData(hItem, (DWORD)node);
      
          // Set button state.
          if (node->hasChildNodes()) {
              HTREEITEM hChildItem = GetTreeCtrl().InsertItem(_T(""), nImage, 
                   nSelectedImage, hItem);
              GetTreeCtrl().SetItemData(hChildItem, (DWORD)NULL);
          }
      
          return hItem;
      }
      
      

    Please don't send emails but post here if you have any questions regarding this article.

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here

    Share

    About the Author

    Frank Le

    United States United States
    No Biography provided

    Comments and Discussions

     
    GeneralA better way Pin
    Member 40403951-Jul-09 16:03
    memberMember 40403951-Jul-09 16:03 
    Generallicense Pin
    avirabinovich19-May-09 6:36
    memberavirabinovich19-May-09 6:36 
    QuestionIn C# Pin
    Prateek Bahl2-Jul-08 11:06
    memberPrateek Bahl2-Jul-08 11:06 
    AnswerRe: In C# Pin
    Prateek Bahl18-Sep-08 6:03
    memberPrateek Bahl18-Sep-08 6:03 
    QuestionIntegration with other classes Pin
    Nilson Bastos Jr1-Apr-08 11:59
    memberNilson Bastos Jr1-Apr-08 11:59 
    GeneralIn VB.net 2005 Pin
    ShailShin11-Jun-06 23:37
    memberShailShin11-Jun-06 23:37 
    GeneralNice, but memory leak... Pin
    eXRange16-Aug-05 18:44
    membereXRange16-Aug-05 18:44 
    GeneralAnother Memory Leak Pin
    Stellar Developer30-Jun-05 9:01
    memberStellar Developer30-Jun-05 9:01 
    Just keep opening different xml files. My files were 50-300K apiece, so it may not show much is small files. but aparently, msxml does not clean up its data (i see it calling Release(), but the memory remains). Im reserching this because allot of the companies code uses msxml. So basically, now the company has a wide spread problem.

    Stellar Developer
    GeneralRe: Another Memory Leak Pin
    pocjoc12-Jul-05 23:40
    memberpocjoc12-Jul-05 23:40 
    Generalsuggestion Pin
    ChauJohnthan7-Apr-05 12:17
    memberChauJohnthan7-Apr-05 12:17 
    GeneralSDI to MDI Pin
    help_cplus17-Nov-04 2:58
    memberhelp_cplus17-Nov-04 2:58 
    GeneralMemory Leak Pin
    mistretzu27-Sep-04 4:07
    membermistretzu27-Sep-04 4:07 
    GeneralMemory Leak Pin
    Anonymous27-Sep-04 4:03
    sussAnonymous27-Sep-04 4:03 
    GeneralDynamic updating of tree with new data Pin
    JRubinstein19-Aug-04 9:27
    memberJRubinstein19-Aug-04 9:27 
    GeneralRe: Dynamic updating of tree with new data Pin
    Anonymous19-Aug-04 13:30
    sussAnonymous19-Aug-04 13:30 
    GeneralRe: Dynamic updating of tree with new data Pin
    JRubinstein19-Aug-04 16:24
    memberJRubinstein19-Aug-04 16:24 
    GeneralDTD Schema Pin
    Bruno II20-Oct-03 4:29
    memberBruno II20-Oct-03 4:29 
    GeneralThe demo project is corrupted Pin
    TW17-Feb-03 0:47
    memberTW17-Feb-03 0:47 
    GeneralLoading an XML file initially Pin
    Chris Hunter17-Oct-02 2:16
    memberChris Hunter17-Oct-02 2:16 
    Generalxml diff Pin
    Murari28-Jun-02 10:30
    memberMurari28-Jun-02 10:30 
    GeneralRe: xml diff Pin
    Anonymous19-Aug-04 13:33
    sussAnonymous19-Aug-04 13:33 
    GeneralModified it to work with the Pocket PC Pin
    mark edwards24-Jan-02 10:25
    membermark edwards24-Jan-02 10:25 
    GeneralRe: Modified it to work with the Pocket PC Pin
    Frank Le11-Mar-02 11:07
    memberFrank Le11-Mar-02 11:07 
    GeneralRe: Modified it to work with the Pocket PC Pin
    nishu5-Aug-02 11:10
    membernishu5-Aug-02 11:10 
    GeneralA way of study Pin
    switch wang5-Sep-01 0:12
    memberswitch wang5-Sep-01 0:12 
    GeneralIt's an old trick Pin
    Tomaz Stih5-Mar-01 0:12
    memberTomaz Stih5-Mar-01 0:12 
    GeneralRe: It's an old trick Pin
    Goblin4-May-01 6:07
    memberGoblin4-May-01 6:07 
    GeneralRe: It's an old trick Pin
    tstih3-Jul-02 7:44
    membertstih3-Jul-02 7:44 
    GeneralRe: It's an old trick Pin
    sage25517-Apr-03 11:35
    membersage25517-Apr-03 11:35 
    Generalspeed, demodata Pin
    real name19-Dec-00 23:14
    memberreal name19-Dec-00 23:14 
    GeneralDOM parser Pin
    Jerry III19-Dec-00 21:19
    memberJerry III19-Dec-00 21:19 
    GeneralRe: DOM parser Pin
    Anonymous20-Dec-00 3:19
    memberAnonymous20-Dec-00 3:19 
    GeneralRe: DOM parser Pin
    real name20-Dec-00 22:18
    memberreal name20-Dec-00 22:18 
    GeneralRe: DOM parser Pin
    Anonymous20-Feb-01 3:02
    memberAnonymous20-Feb-01 3:02 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

    | Advertise | Privacy | Terms of Use | Mobile
    Web02 | 2.8.150520.1 | Last Updated 8 Jun 2000
    Article Copyright 2000 by Frank Le
    Everything else Copyright © CodeProject, 1999-2015
    Layout: fixed | fluid