Click here to Skip to main content
15,901,893 members
Articles / Desktop Programming / MFC
Article

XML as a collection

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
15 May 20022 min read 81K   1.9K   26   7
A class for reading and writing XML files

Introduction

If you ever dreamed about a simple MFC-Based collection to handle an ANSI XML file then here is the solution.

CXXMLFile : (Class) eXtended XML File

This class reads simple XML files. It assumes the HTML/XML conventions in symbols and tags. But, the tag <? .... ?> is ignored for now. This means that no codepage support is available (to make code simpler).

When CXXMLFile reads a file it creates a tag tree with tree types of nodes:

 

Image 1

Legend:

  1. CElementPart. Abstract base class for all node types. It includes the common member variable 'm_Text'.
  2. CText. Derived from CElementPart. It represents a piece of text, it can be surrounded by any kind of nodes. Symbol replacement will be applied here, for example &nbsp; in HTML code.
  3. CComment. A comment in form <!--something-->. It is not affected by symbol replacement.
  4. CElement. A tag. It has three properties:
    m_Text
    
    (the tag name), AttributeMap(A string map atname -> at value), and by inheritance a CList of Nodes.

Then, only a CElement node type should have children.

CXXMLFile Class Reference

List of all members.

Public Methods

CXXMLFile ()
Constructor.

virtual ~CXXMLFile ()
Destructor.

void RemoveAll ()
Delete all entries and make a default root node.

void AddSymbol (CString coded, CString decoded)
Adds a symbol.

void DefaultSymbols ()
Set default symbols.

void ClearSymbols ()
Clear symbols.

void AddOpenTag (CString tag)
Adds an open tag. (HTML ).

bool Write ()
Writes XML file.

CString GetFile ()
Get XML filename.

void SetFile (CString filename)
Set XML filename.

bool Read ()
The read XML function.

 

CElementPart * Root ()
Gets the root. (Create one if it's empty).

CElementPart * AddElement (CElementPart *Parent)
Adds a node type element.

CElementPart * AddComment (CElementPart *Parent, CString text)
Adds a comment node.

CElementPart * AddText (CElementPart *Parent, CString text)
Adds a text node.

void SetText (CElementPart *node, CString text)
Sets text property in a node.

void GetText (CElementPart *node, CString &text)
Gets text property in a node.

bool IsElement (CElementPart *node)
Determines wheter node is element.

bool IsComment (CElementPart *node)
Determines wheter node is comment.

bool IsText (CElementPart *node)
Determines wheter node is text.

CMapStringToString * GetElementAttrMap (CElementPart *node)
Returns a pointer to the attribute map of the element.

bool BuildChildList (CElementPart *node, CList< CElementPart *, CElementPart * > &l)
Builds a list of child nodes.

 

Public Attributes

CStringList m_ErrorList

Private Methods

void Decodify (CString &html)
Decodify using symbol table.

void Codify (CString &html)
Codify using symbol table.

void WritePart (CStdioFile *f, CElementPart *p, int Depth, bool bNoIdent=false)
Writes an XML node to a file (used by Write only).

Private Attributes

CElementPart * m_Root
CMapStringToString m_Symbols
CString m_Filename
CMapStringToString m_OpenTags

Header

// XXMLFile.h: interface for the CXXMLFile class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_XXMLFILE_H__F5E3CD25_0B84_4191_A1A7_B3669180DFFA__INCLUDED_)
#define AFX_XXMLFILE_H__F5E3CD25_0B84_4191_A1A7_B3669180DFFA__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <afxtempl.h>


//************************************************************************//
/*!  \class CXXMLFile
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief A class to work with XML files as tree collections.
 */
class CXXMLFile  {
public:
    CXXMLFile();
    virtual ~CXXMLFile();
public:
    // Abstract node
    class CElementPart;
    class CElementPart{
    public:
        CElementPart* m_Parent;
        CString m_Text;
        enum TType { TElement, TText, TComment } m_Type;
    public:
        CElementPart(){};
        virtual ~CElementPart(){};
    };

    // Element node
    class CElement : public CElementPart, public CList<CElementPart*,CElementPart*>{
    public:
        CElement(){ m_Type=TElement; };
        virtual ~CElement();
    public:
        CMapStringToString AttributeToValue;
    };

    // Text node
    class CText : public CElementPart{
    public:
        CText(){ m_Type=TText; };
    };

    // Comment node
    class CComment : public CElementPart{
    public:
        CComment(){ m_Type=TComment; };
    };
public:
    // The error list, after executing Write() or Read() (if any)
    CStringList m_ErrorList;

    // Symbol table functions
    void RemoveAll();
    void AddSymbol(CString coded, CString decoded);
    void DefaultSymbols();
    void ClearSymbols();
    void AddOpenTag(CString tag);

    // File manipulation routines
    bool Write();
    CString GetFile();
    void SetFile(CString filename);
    bool Read();

    // Tree manipulation routines
    CElementPart* Root();
    CElementPart* AddElement(CElementPart* Parent);
    CElementPart* AddComment(CElementPart* Parent, CString text);
    CElementPart* AddText(CElementPart* Parent, CString text);
    void SetText(CElementPart* node, CString text);
    void GetText(CElementPart* node, CString &text);
    bool IsElement(CElementPart* node);
    bool IsComment(CElementPart* node);
    bool IsText(CElementPart* node);
    CMapStringToString* GetElementAttrMap(CElementPart* node);
    bool BuildChildList(CElementPart* node, CList<CElementPart*,CElementPart*> &l);
private:
    // The XML tree
    CElementPart* m_Root;

    // Symbol codification functions
    void Decodify(CString &html);
    void Codify(CString &html);
    CMapStringToString m_Symbols; // encoded to decoded

    // Part management
    void WritePart(CStdioFile *f, CElementPart * p, int Depth, bool bNoIdent=false);

    // Filename
    CString m_Filename;

    // Open tags map (acts like a set, so second value is ignored)
    CMapStringToString m_OpenTags;
};

#endif // !defined(AFX_XXMLFILE_H__F5E3CD25_0B84_4191_A1A7_B3669180DFFA__INCLUDED_)

Source

// XXMLFile.cpp: implementation of the CXXMLFile class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "XXMLFile.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////


//************************************************************************//
/*!  \fn CXXMLFile::CXXMLFile()
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Constructor
 */
CXXMLFile::CXXMLFile()
{
    // The root is null
    m_Root=NULL;

    // clean tables, and create a default root node
    RemoveAll();

    // set default symbols and open tags
    DefaultSymbols();
}


//************************************************************************//
/*!  \fn CXXMLFile::~CXXMLFile()
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Destructor
 */
CXXMLFile::~CXXMLFile()
{
    // clean up root (and then, the full tree)
    if(m_Root!=NULL) delete m_Root;
}


//************************************************************************//
/*!  \fn CXXMLFile::CElement::~CElement()
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Element destructor (clean up the list of elements)
 */
CXXMLFile::CElement::~CElement(){
    // You must clean up the possible list of elements
    while(!IsEmpty()) delete RemoveHead();
};


//************************************************************************//
/*!  \fn bool IsSeparator(char ch){
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Ask for an XML separator 
 */
static bool IsSeparator(char ch){
    switch (ch){
    case ' ': return true;
    case '\t': return true;
    case '\r': return true;
    case '\n': return true;
    default: return false;
    };
};

//************************************************************************//
/*!  \fn bool HopSeparators(CString &html, int &pos,int FileRow)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief For internal use (Read()). It jumps over separators in a string by 
 * incrementing an integer pointer.
 */
static bool HopSeparators(CString &html, int &pos,int FileRow){
    while( (pos<html.GetLength()) && (IsSeparator(html.GetAt(pos))) ){
        if(html.GetAt(pos)=='\n') 
            FileRow++;
        pos++;
    }
    if(pos>=html.GetLength()) return false; else return true;
};

//************************************************************************//
/*!  \fn int CountChars(CString s,char ch)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief A brute-force character counter.
 */
static int CountChars(CString s,char ch){
    return s.Replace(CString()+ch,"");
};

//************************************************************************//
/*!  \fn int FindChars(CString &html, int pos, LPCTSTR chars)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief For internal use (Read()). It secuentially look for any char in 
 * a given set from an starting pointer in a string.
 */
static int FindChars(CString &html, int pos, LPCTSTR chars){
    int tmp=pos;
    CString seps = chars;
    while(tmp<html.GetLength()) {
        if(seps.FindOneOf( CString(html.GetAt(tmp)) )!=-1){
            return tmp;
        }
        tmp++;
    }
    return -1;
};


//************************************************************************//
/*!  \fn bool CXXMLFile::Read()
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief The read XML function.
 */
bool CXXMLFile::Read()
{
    CString filename = m_Filename;
    int FileRow=1;

    // Init Tree
    if(m_Root!=NULL) delete m_Root;
    CElementPart** crut = &m_Root;
    CElement* Element = new CElement();
    Element->m_Parent=(*crut);
    (*crut)=Element;
    ((CElement*)(*crut))->m_Text = "?root?";

    // Clean up errors
    m_ErrorList.RemoveAll();

    // A brute-force reading of a text file (the most faster)
    CString html;
    TRY{
        CFile * f = new CFile(filename,CFile::modeRead|CFile::shareDenyNone);
        if(f==NULL) ::AfxThrowFileException(CFileException::fileNotFound,-1,filename);
        html.Empty();
        char * buf = html.GetBufferSetLength(f->GetLength());
        f->SeekToBegin();
        f->Read(buf,f->GetLength());
        f->Close();
        delete f;
        html.ReleaseBuffer();
        html.FreeExtra();
        html.Replace("\r\n","\n");
    }CATCH_ALL(e){
        m_ErrorList.AddTail("Error: File not found.");
        return false;
    }END_CATCH_ALL

    int p1,p2,p3,p4;
    p1=p2=p3=p4=0;
    while(true){
        if(p1>=html.GetLength()) return true;
        p2 = html.Find('<',p1);
        if(p2==-1){
            m_ErrorList.AddTail("Warning at line "+CString(FileRow)+
                ": There's some text before EOF, ignoring.");
            return true;
        } 
        CString text = html.Mid(p1,p2-p1);
        Decodify(text);
        if(!text.IsEmpty()){
            if( (*crut)==NULL ){
                m_ErrorList.AddTail("Warning at line "+CString(FileRow)
                +": No tag active but text found, must be at the start, ignoring.");
            } else {
                CText * t = new CText();
                t->m_Text = text;
                ((CElement*)(*crut))->AddTail( t );
                FileRow+=CountChars(text,'\n');
            }
        }

        // tag part
        p1=p2+1;
        if(p1>=html.GetLength()){ 
            m_ErrorList.AddTail("Error at line "+CString(FileRow)+
                ": Tag started buf EOF found.");
            return false;
        } else
        if(html.Mid(p1,3)=="!--"){ // comment
            p1=p1+3;
            p2 = html.Find("-->",p1);
            CString text = html.Mid(p1,p2-p1);
            if(p2==-1){
                m_ErrorList.AddTail("Error at line "+CString(FileRow)+
                    ": Comment tag unclosed.");
                return false;
            }
            if( (*crut)==NULL ){
                m_ErrorList.AddTail("Warning at line "+CString(FileRow)+
                    ": No tag active but text found, ignoring.");
            } else {
                CComment * t = new CComment();
                t->m_Text = text;
                ((CElement*)(*crut))->AddTail( t );
                FileRow+=CountChars(text,'\n');
            }
            p1=p2+=3;
        } else 
        if(html.GetAt(p1)=='?'){ // ?xml or something to avoid
            p2 = html.Find("?>",p1+1);
            if(p2==-1){
                m_ErrorList.AddTail("Error at line "+CString(FileRow)+
                    ": Tag <? unclosed.");
                return false;
            } else {
                p1=p2+2;
                continue;
            }
        } else 
        if(html.GetAt(p1)=='/'){ // an end tag
            p2 = html.Find('>',p1);
            if(p2==-1){
                m_ErrorList.AddTail("Error at line "+CString(FileRow)+
                    ": Tag unclosed.");
                return false;
            }
            p1++;
            CString tagname = html.Mid(p1,p2-p1);
            tagname.TrimLeft();
            tagname.TrimRight();
            if( (*crut)==NULL ){
                m_ErrorList.AddTail("Error at line "+CString(FileRow)+
                    ": Closing tag when no tag???.");
                return false;
            }
            if( (*crut)->m_Text!=tagname ){
                m_ErrorList.AddTail("Error at line "+CString(FileRow)+
                    ": Closing tag differs from open tag.");
                return false;
            }
            (*crut)=(*crut)->m_Parent;
            p1=p2+1;
        } else { // a start tag
            // < _ tag ...
            if(!HopSeparators(html,p1,FileRow)){
                m_ErrorList.AddTail("Error at line "+CString(FileRow)+
                    ": Unspected EOF.");
                return false;
            }
            // < tag _ ...
            p2=FindChars(html,p1," \t\r\n>");
            if(p2==-1){
                m_ErrorList.AddTail("Error at line "+CString(FileRow)+
                    ": Unspected EOF.");
                return false;
            }
            CString tag = html.Mid(p1,p2-p1);             
            CElement* Element = new CElement();
            Element->m_Parent=(*crut);
            ((CElement*)(*crut))->AddTail( ((CElementPart*)Element) );
            (*crut)=Element;
            ((CElement*)(*crut))->m_Text = tag;
            p1=p2;
            while(true){
                // _ >... 
                // _ value="...
                if(!HopSeparators(html,p1,FileRow)){
                    m_ErrorList.AddTail("Error at line "+
                        CString(FileRow)+": Unspected EOF.");
                    return false;
                }
                if(html.GetAt(p1)=='>'){
                    // _ >... 
                    p1+=1;
                    tag.MakeLower(); // tag string will be no longer used
                    CString value;
                    if(m_OpenTags.Lookup(tag,value)){
                        // It's an open tag, that means that it will never be closed
                        // Eg: <br> in HTML
                        (*crut)=(*crut)->m_Parent; // closing node
                    }
                    break;
                };
                if(html.Mid(p1,2)=="/>"){
                    // _ />... 
                    // This kind of tag means that no close tag is expected.
                    p1+=2;
                    (*crut)=(*crut)->m_Parent; // collapse node
                    break;
                };
                // _ value="...
                p2=html.Find("=\"",p1);
                if(p2==-1){
                    m_ErrorList.AddTail("Error at line "+CString(FileRow)+
                        ": Unspected value form.");
                    return false;
                }
                CString valname = html.Mid(p1,p2-p1);
                valname.TrimLeft();
                valname.TrimRight();
                p1=p2+2;
                CString value;
                while(true){
                    if(p1>=html.GetLength()){
                        m_ErrorList.AddTail("Error at line "+
                            CString(FileRow)+": Unspected EOF.");
                        return false;
                    } else
                    if(html.GetAt(p1)=='\"'){
                        p1++;
                        break;
                    } else
                    if(html.Mid(p1,2)=="\\\""){
                        value+="\"";
                        p1+=2;
                    } else {
                        value+=html.GetAt(p1);
                        p1++;
                    }
                }
                Element->AttributeToValue[valname]=value;
            }
        }
    }
}


//************************************************************************//
/*!  \fn void CXXMLFile::SetFile(CString filename)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Set XML filename.
 */
void CXXMLFile::SetFile(CString filename)
{
    m_Filename=filename;
}


//************************************************************************//
/*!  \fn CString CXXMLFile::GetFile()
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Get XML filename.
 */
CString CXXMLFile::GetFile()
{
    return m_Filename;
}


//************************************************************************//
/*!  \fn void CXXMLFile::WritePart(CStdioFile *f, CXXMLFile::CElementPart * p, 
 *                                 int Depth, bool bNoIdent){
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Writes an XML node to a file (used by Write only).
 *
 *   \param f The target file.
 *   \param p The tree node.
 *   \param Depth The node depth (for identation).
 *   \param bNoIdent Boolean value used to cancel identation if the node is alone,
 * that is, without children and siblings.
 */
void CXXMLFile::WritePart(CStdioFile *f, CElementPart * p, int Depth, bool bNoIdent){
    int j;
    if(p->m_Type==CElementPart::TElement){
        {// Write identation
            // Avoid line-feed at the begining of the file
            if(f->GetPosition()!=0) 
                f->WriteString("\n"); 
            // the Identation with spaces
            for(j=0;j<Depth;j++) 
                f->WriteString(" ");
        }
        // Write tag header
        f->WriteString("<"+p->m_Text);

        // Write values
        POSITION pos = ((CElement*)p)->AttributeToValue.GetStartPosition();
        while(pos!=NULL){
            CString AtName,AtValue;
            ((CElement*)p)->AttributeToValue.GetNextAssoc(pos,AtName,AtValue);
            f->WriteString(" "+AtName+"=\""+AtValue+"\"");
        };

        // If the Element does not have subelements, sub-texts, or sub-comments
        // write it closed
        if(((CElement*)p)->IsEmpty()) {
            // Is an open tag (like HTML <br>)?
            CString tag;
            tag = p->m_Text;
            tag.MakeLower();
            CString value;
            if(m_OpenTags.Lookup(tag,value)){
                // It's an open tag, that means that it will 
                // never be closed Eg: <br> in HTML
                f->WriteString(">");
            } else {
                // Not an open tag
                f->WriteString("/>");
            }
        } else {
            f->WriteString(">");

            // Optimization to block ident on single subtext in element.
            bool NoIdent = false;
            if(((CElement*)p)->GetCount()==1)
                NoIdent=true;

            // For each element...
            pos = ((CElement*)p)->GetHeadPosition();
            while(pos!=NULL){
                CElementPart*e = ((CElement*)p)->GetAt(pos);
                WritePart(f,e,Depth+1,NoIdent);
                ((CElement*)p)->GetNext(pos);
            }

            // Optimization to block ident on single subtext in element.
            if(!NoIdent){
                {// Write identation
                    // Avoid line-feed at the begining of the file
                    if(f->GetPosition()!=0) 
                        f->WriteString("\n"); 
                    // the Identation with spaces
                    for(j=0;j<Depth;j++) 
                        f->WriteString(" ");
                }            
            }

            // Close tag
            f->WriteString("</"+p->m_Text+">");
        }
    } else 
    if(p->m_Type==CElementPart::TComment){
        // Write comment AS-IS
        {// Write identation
            // Avoid line-feed at the begining of the file
            if(f->GetPosition()!=0) 
                f->WriteString("\n"); 
            // the Identation with spaces
            for(j=0;j<Depth;j++) 
                f->WriteString(" ");
        }
        f->WriteString("<!--"+p->m_Text+"-->");
    } else 
    if(p->m_Type==CElementPart::TText){
        // Write text if it's not empty (an empty text can have sparators)
        CString empty_string = p->m_Text;
        empty_string.Replace('\n',' ');
        empty_string.Replace('\r',' ');
        empty_string.Replace('\t',' ');
        while(0!=empty_string.Replace("  "," "));
        if((!empty_string.IsEmpty())&&(empty_string!=" ")) {
            if(!bNoIdent){
                {// Write identation
                    // Avoid line-feed at the begining of the file
                    if(f->GetPosition()!=0) 
                        f->WriteString("\n"); 
                    // the Identation with spaces
                    for(j=0;j<Depth;j++) 
                        f->WriteString(" ");
                }
            }

            // The string must be written with symbol codification
            CString text = p->m_Text;
            Codify(text);
            f->WriteString(text);
        }
    } 
};


//************************************************************************//
/*!  \fn bool CXXMLFile::Write()
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Writes XML file.
 */
bool CXXMLFile::Write()
{
    m_ErrorList.RemoveAll();

    // check tree
    if(m_Root==NULL) {
        m_ErrorList.AddTail("Error: NULL tree.");
        return false;
    }
    if(m_Root->m_Type!=CElementPart::TElement) {
        m_ErrorList.AddTail("Error: tree root is not an Element.");

        return false; // root must be TElement
    }
    if(((CElement*)m_Root)->m_Text!="?root?") {
        m_ErrorList.AddTail("Error: tree root is not named ?root?");
        return false; // bad-written root
    }

    // Ok write file;
    CStdioFile * f = new CStdioFile(m_Filename,CFile::modeCreate|
            CFile::modeWrite|CFile::shareDenyNone|CFile::typeText);
    if(f==NULL){
        m_ErrorList.AddTail("Error: cannot open '"+m_Filename+"' for writing.");
        return false; 
    } 

    CElement * root = ((CElement*)m_Root);
    POSITION pos = root->GetHeadPosition();
    while(pos!=NULL){
        CElementPart * p = root->GetAt(pos);
        WritePart(f,p,0);
        root->GetNext(pos);
    }

    f->Close();
    delete f;

    return true;
}


//************************************************************************//
/*!  \fn void CXXMLFile::DefaultSymbols()
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Set default symbols.
 */
void CXXMLFile::DefaultSymbols()
{
    AddSymbol("&lt;","<");
    AddSymbol("&gt;",">");
    AddSymbol("&quot;","\"");
    AddSymbol(" "," ");
    AddSymbol("&apos;","'");
    AddSymbol("&amp;","&");
    m_OpenTags["br"];
}


//************************************************************************//
/*!  \fn void CXXMLFile::ClearSymbols()
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Clear symbols.
 */
void CXXMLFile::ClearSymbols()
{
    // Clear symbol table
    m_Symbols.RemoveAll();

    // Remove open tags
    m_OpenTags.RemoveAll();
}


//************************************************************************//
/*!  \fn void CXXMLFile::AddSymbol(CString coded, CString decoded)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Adds a symbol.
 */
void CXXMLFile::AddSymbol(CString coded, CString decoded)
{
    m_Symbols[coded]=decoded;
}


//************************************************************************//
/*!  \fn void CXXMLFile::RemoveAll()
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Delete all entries and make a default root node.
 */
void CXXMLFile::RemoveAll()
{
    // Clear symbol table
    ClearSymbols();

    // Remove open tags
    m_OpenTags.RemoveAll();

    // Clear tree and create the default main node
    if(m_Root!=NULL) delete m_Root;
    CElementPart** crut = &m_Root;
    CElement* Element = new CElement();
    Element->m_Parent=(*crut);
    (*crut)=Element;
    ((CElement*)(*crut))->m_Text = "?root?";
}


//************************************************************************//
/*!  \fn void CXXMLFile::Codify(CString &html)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Codify using symbol table.
 */
void CXXMLFile::Codify(CString &html)
{
    int pos = 0;
    while(pos<html.GetLength()){
        POSITION p = m_Symbols.GetStartPosition();
        while(p!=NULL){
            CString coded, decoded;
            m_Symbols.GetNextAssoc(p,coded,decoded);
            if((pos+decoded.GetLength())<=html.GetLength()){
                if(html.Mid(pos,decoded.GetLength())==decoded){
                    html = html.Left(pos) + coded + 
                        html.Mid(pos+decoded.GetLength());
                    pos = pos + coded.GetLength()-1;
                    break;
                }
            }
        }
        pos++;
    }
}


//************************************************************************//
/*!  \fn void CXXMLFile::Decodify(CString &html)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Decodify using symbol table.
 */
void CXXMLFile::Decodify(CString &html)
{
    int pos = 0;
    while(pos<html.GetLength()){
        POSITION p = m_Symbols.GetStartPosition();
        while(p!=NULL){
            CString coded, decoded;
            m_Symbols.GetNextAssoc(p,coded,decoded);
            if((pos+coded.GetLength())<=html.GetLength()){
                if(html.Mid(pos,coded.GetLength())==coded){
                    html = html.Left(pos) + decoded + 
                        html.Mid(pos+coded.GetLength());
                    pos = pos + decoded.GetLength()-1;
                    break;
                }
            }
        }
        pos++;
    }
}

//************************************************************************//
/*!  \fn void CXXMLFile::AddOpenTag(CString tag)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Adds an open tag. (HTML <br>)
 */
void CXXMLFile::AddOpenTag(CString tag){
    tag.MakeLower();
    m_OpenTags[tag];
}

//************************************************************************//
/*!  \fn CXXMLFile::CElementPart* CXXMLFile::Root()
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Gets the root. (Create one if it's empty).
 */
CXXMLFile::CElementPart* CXXMLFile::Root(){
    if(m_Root!=NULL) 
        return (CXXMLFile::CElementPart*)m_Root;
    CElementPart** crut = &m_Root;
    CElement* Element = new CElement();
    Element->m_Parent=(*crut);
    (*crut)=Element;
    ((CElement*)(*crut))->m_Text = "?root?";
    return Element;
}

//************************************************************************//
/*!  \fn CXXMLFile::CElementPart* CXXMLFile::AddElement(CElementPart* Parent)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Adds a node type element
 */
CXXMLFile::CElementPart* CXXMLFile::AddElement(CElementPart* Parent){
    // Only TElement nodes support childs
    if(Parent->m_Type!=CXXMLFile::CElementPart::TElement)
        return NULL;
    CXXMLFile::CElement * elem = (CXXMLFile::CElement*)Parent;    
    CXXMLFile::CElement * new_elem = new CElement();
    elem->AddTail( ((CXXMLFile::CElementPart*)new_elem) );
    return new_elem;
}


//************************************************************************//
/*!  \fn void CXXMLFile::SetText(CElementPart* node, CString text)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Sets text property in a node.
 */
void CXXMLFile::SetText(CElementPart* node, CString text){
    node->m_Text = text;
};

//************************************************************************//
/*!  \fn void CXXMLFile::GetText(CElementPart* node, CString &text)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Gets text property in a node.
 */
void CXXMLFile::GetText(CElementPart* node, CString &text){
    text = node->m_Text;
};

//************************************************************************//
/*!  \fn CXXMLFile::CElementPart* CXXMLFile::AddComment(CElementPart* Parent, 
 *                                                      CString text)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Adds a comment node
 */
CXXMLFile::CElementPart* CXXMLFile::AddComment(CElementPart* Parent, CString text){
    // Only TElement nodes support childs
    if(Parent->m_Type!=CXXMLFile::CElementPart::TElement)
        return NULL;
    CXXMLFile::CElement * elem = (CXXMLFile::CElement*)Parent;    
    CXXMLFile::CComment * new_elem = new CComment();
    elem->AddTail( ((CXXMLFile::CElementPart*)new_elem) );
    return new_elem;
};

//************************************************************************//
/*!  \fn CXXMLFile::CElementPart* CXXMLFile::AddText(CElementPart* Parent,
 *                                                   CString text)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Adds a text node
 */
CXXMLFile::CElementPart* CXXMLFile::AddText(CElementPart* Parent, CString text){
    // Only TElement nodes support childs
    if(Parent->m_Type!=CXXMLFile::CElementPart::TElement)
        return NULL;
    CXXMLFile::CElement * elem = (CXXMLFile::CElement*)Parent;    
    CXXMLFile::CText * new_elem = new CText();
    elem->AddTail( ((CXXMLFile::CElementPart*)new_elem) );
    return new_elem;
}

//************************************************************************//
/*!  \fn bool CXXMLFile::IsElement(CElementPart* node)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief  Determines wheter node is element. 
 */
bool CXXMLFile::IsElement(CElementPart* node)
{
    return (node->m_Type==CXXMLFile::CElementPart::TElement);
}

//************************************************************************//
/*!  \fn bool CXXMLFile::IsComment(CElementPart* node)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Determines wheter node is comment. 
 */
bool CXXMLFile::IsComment(CElementPart* node)
{
    return (node->m_Type==CXXMLFile::CElementPart::TComment);
}

//************************************************************************//
/*!  \fn bool CXXMLFile::IsText(CElementPart* node)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Determines wheter node is text. 
 */
bool CXXMLFile::IsText(CElementPart* node)
{
    return (node->m_Type==CXXMLFile::CElementPart::TText);
}

//************************************************************************//
/*!  \fn CMapStringToString* CXXMLFile::GetElementAttrMap(CElementPart* node)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Returns a pointer to the attribute map of the element.
 */
CMapStringToString* CXXMLFile::GetElementAttrMap(CElementPart* node)
{
    // Only TElement nodes support childs
    if(node->m_Type!=CXXMLFile::CElementPart::TElement)
        return NULL;
    CXXMLFile::CElement * elem = (CXXMLFile::CElement*)node;    
    return &elem->AttributeToValue;
}

//************************************************************************//
/*!  \fn bool CXXMLFile::BuildChildList(CElementPart* node, 
 *                                      CList<CElementPart*,CElementPart*> &l)
 *   \author Manuel Lucas Viñas Livschitz (MLVL)
 *   \date 04/05/2002
 *   \brief Builds a list of child nodes.
 */
bool CXXMLFile::BuildChildList(CElementPart* node, 
                               CList<CElementPart*,CElementPart*> &l)
{
    // Only TElement nodes support childs
    if(node->m_Type!=CXXMLFile::CElementPart::TElement)
        return false;
    l.RemoveAll();
    l.AddTail( ((CElementPart*)node) );
    return true;
}

Example

The most simple example is in trying to load an XML file, converting in a CXMLFile collection and then writing back an XML file.

We will do the test with books.xml (from MSDN XML SDK)

Source code (extract)

// XMLTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "XMLTest.h"

....

// read-write test
        CXXMLFile xml;
        xml.SetFile("books.xml");
        bool bok = xml.Read();

        if(!bok){
            POSITION pos = xml.m_ErrorList.GetHeadPosition();
            while(pos!=NULL){
                printf(xml.m_ErrorList.GetAt(pos)+"\n");
                xml.m_ErrorList.GetNext(pos);
            }
        } else {
            xml.SetFile("books_out.xml");
            xml.ClearSymbols(); // no html symbols (to avoid convering spaces into  
            bok = xml.Write();
            if(!bok){
                POSITION pos = xml.m_ErrorList.GetHeadPosition();
                while(pos!=NULL){
                    printf(xml.m_ErrorList.GetAt(pos)+"\n");
                    xml.m_ErrorList.GetNext(pos);
                }
            }
        }

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


Written By
Web Developer
Spain Spain
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralAccess to the XML collection Pin
Olivier Simon14-Jun-05 5:25
Olivier Simon14-Jun-05 5:25 
GeneralHelp for your &quot;XML as a collection&quot; Pin
CorkyManu20-Apr-05 2:56
CorkyManu20-Apr-05 2:56 
GeneralHelp! New XML Document Pin
miyuru22-Jan-04 1:58
miyuru22-Jan-04 1:58 
Generalerror C2440: 'type cast' : cannot convert from 'int' to 'ATL::CStringT' Pin
Ogi10-Jan-03 4:33
Ogi10-Jan-03 4:33 
GeneralRe: error C2440: 'type cast' : cannot convert from 'int' to 'ATL::CStringT' Pin
M L Viñas Livschitz10-Jan-03 9:09
M L Viñas Livschitz10-Jan-03 9:09 
GeneralRe: error C2440: 'type cast' : cannot convert from 'int' to 'ATL::CStringT' Pin
Moby3-Jun-03 0:36
Moby3-Jun-03 0:36 
GeneralRe: error C2440: 'type cast' : cannot convert from 'int' to 'ATL::CStringT' Pin
Moby3-Jun-03 0:40
Moby3-Jun-03 0:40 
You can also create a new member function:

void CXXMLFile::AddErr(CString msg, int Row)
{
CString strErr;
strErr.Format(msg, Row);
m_ErrorList.AddTail(strErr);
}


Syncerely yours,

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

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