Click here to Skip to main content
Click here to Skip to main content
Go to top

How To Serialize a CTreeCtrl in XML

, 3 May 2006
Rate this:
Please Sign up or sign in to vote.
Extend derived CTreeCtrl classes with an easy and fast to use approach for XML serialisation.
Sample Image - ctreectrl_xml.jpg

Introduction

For this tutorial, you'll need basic knowledge of the XML format.

A while ago, I had to come up with a solution on how to serialize a CTreeCtrl - or a derived class from it - with XML, e.g. loading and saving its content in an XML file without destroying the tree structure of the items.

Browsing the web did not give me any hints on how to do this, so I decided to write my own routines for storing CTreeCtrl contents into a file: the class CTreeCtrlXML was born.

As my program had to be fairly small and without big overheads and dependencies, I chose TinyXML to do all the dirty XML parsing and saving stuff. This library is - you maybe suspected it already - very small, easy to integrate in existing projects and more or less platform independent. Also, it's open source under the Zlib license.

You can get TinyXML here.

Implementation

To stay on focus, I developed a small program which demonstrates the functionality of the following two functions:

// Loads all items from an XML file into the tree control and restores its
// original structure. Returns true on success, false if an error occurred.
bool CTreeCtrlXML::LoadFromXML( const CString& a_strFile )
{
    TiXmlNode* pXML = NULL;
    TiXmlDocument xmlDoc;

    char szBuf[ _MAX_PATH + 1 ];
    CString strTemp = a_strFile;

    getcwd( szBuf, sizeof( szBuf ) );
    strcat( szBuf, "\\" );
    strcat( szBuf, strTemp.GetBuffer( 1 ) );

    if( xmlDoc.LoadFile( szBuf ) )
    {
        // XML root
        pXML = xmlDoc.FirstChild( "XML" );

        if( NULL == pXML )
            return false;

        // Load our tree control
        Load( pXML );

        // Expand all entries
        Expand( GetRootItem(), TVE_EXPAND );

        return true;
    }
    
    return false;
}
// Saves all CTreeCtrl contents into an XML file with the name given by a_strFile.
// Returns true on success, false if an error occurred.
bool CTreeCtrlXML::SaveToXML( const CString& a_strFile )
{
    // Save XML
    TiXmlNode* pXML = NULL;
    TiXmlDocument xmlDoc;

    // XML header
    xmlDoc.InsertEndChild( TiXmlDeclaration( "1.0", "UTF-8", "yes" ) );

    // XML root
    pXML = xmlDoc.InsertEndChild( TiXmlElement( "XML" ) );

    // Save our tree control
    Save( pXML );

    // Save XML
    CString strFile = a_strFile;

    return xmlDoc.SaveFile( strFile.GetBuffer( 1 ) );
}

To make the class a bit more useful for your own projects, I also added two functions which need a pointer to an existing XML node. These functions use the node pointers as their XML root, so this makes it extremely easy to immigrate the CtrlTreeXML serialization into existing XML files:

void CTreeCtrlXML::Load( TiXmlNode* a_pNode )
{
    ASSERT( NULL != a_pNode );

    // Get node "Items"
    TiXmlNode* pItems = a_pNode->FirstChild( "Items" );
    TiXmlNode* pItem = NULL;

    if( NULL == pItems )
        return;

    // Get first item
    pItem = pItems->FirstChild( "Item" );

    // Iterate all siblings
    while( NULL != pItem )
    {
        LoadItem( pItem, NULL );
        pItem = pItem->NextSibling( "Item" );
    }
}

void CTreeCtrlXML::Save( TiXmlNode* a_pNode )
{
    ASSERT( NULL != a_pNode );

    TiXmlNode* pItems = a_pNode->InsertEndChild( TiXmlElement( "Items" ) );
    TiXmlNode* pParent = pItems;
    TiXmlNode* pNewNode = NULL;
    HTREEITEM hItem = GetRootItem();
    int iIndent = 0; int iLastIndent = 0;

    while( hItem )
    {
        iIndent = GetIndentLevel( hItem );

        int iDiff = iIndent - iLastIndent;
        if( iDiff > 0 )
        {
            ASSERT( NULL != pNewNode );

            while( iDiff-- )
                pNewNode = pNewNode->InsertEndChild( TiXmlElement( "Item" ) );

            ASSERT( NULL != pNewNode );
            pParent = pNewNode->Parent();
        }
        else if( iDiff < 0 )
        {
            iDiff--;                    // Correct difference to get the right parent
            pParent = pNewNode;

            while( iDiff++ < 0 )
                pParent = pParent->Parent();

            ASSERT( NULL != pParent );
            pNewNode = pParent->InsertEndChild( TiXmlElement( "Item" ) );
        }
        else 
        {
            ASSERT( NULL != pParent );
            pNewNode = pParent->InsertEndChild( TiXmlElement( "Item" ) );
        }

        iLastIndent = iIndent;            

        // Save current item
        TiXmlElement* pElement = pNewNode->ToElement();
        ASSERT( NULL != pElement );

        pElement->SetValue( "Item" );
        pElement->SetAttribute( "Title", GetItemText( hItem ) );

        // The next item, please ...
        hItem = GetNextItem( hItem );
    }
}

Since XML is very extensible, you could store all your configuration data into an XML file, the tree control then would be only a small part of it.

The demo application shows you how to load and save CTreeCtrl's content into two different files: Loading is done from "tree.xml", the data is then saved to "save.xml".

History

  • 3rd May, 2006: Initial post 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Andreas Loeffler
Web Developer
Germany Germany
I was born in 1982 near Stuttgart / Germany and began my first steps in programming computers at the age of only nine years on an old Commodore CBM 7072. In 2002 I finished my education as IT specialist for software engineering and did my civillian service afterwards. Currently I'm working as leader of the software division in a bigger company located in south west Germany, mainly on software development and research projects for multimedia terminals and user recognition/verification systems.

Comments and Discussions

 
GeneralVery nice job! PinmemberVinhTran_31-Aug-14 16:41 
QuestionGood Jobbbbbbbbbbb! Pinmemberq_orange29-Jul-14 22:33 
GeneralNice PinmemberSteve_Harris12-Jul-07 0:08 
GeneralGetting Error.......!!! Pinmembersyampj17-Apr-07 18:28 
GeneralRe: Getting Error.......!!! PinmemberAndreas Loeffler17-Apr-07 20:54 
QuestionHow to get the item node when selection changed? PinmemberLinux dotMicrosoft21-Aug-06 21:37 
Generaltree.xml problems Pinmembersad61t9-May-06 0:41 
The project only seems to load its own tree.xml file.
 
If I try to load a different XML file, e.g. the CTreeCtrlXML.vcproj file renamed to tree.xml, then the application reports:
'Aaarrgh ...','Could not load XML file!\nPlease make sure that a valid XML file call "tree.xml" is present!',MB_OK|MB_ICONSTOP

GeneralRe: tree.xml problems Pinmemberbenjymous9-May-06 0:57 
GeneralRe: tree.xml problems PinmemberAndreas Loeffler11-May-06 7:29 

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 | Mobile
Web01 | 2.8.140905.1 | Last Updated 3 May 2006
Article Copyright 2006 by Andreas Loeffler
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid