XML as a collection





5.00/5 (1 vote)
May 16, 2002
2 min read

81381

1914
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:
Legend:
CElementPart
. Abstract base class for all node types. It includes the common member variable 'm_Text
'.CText
. Derived fromCElementPart
. It represents a piece of text, it can be surrounded by any kind of nodes. Symbol replacement will be applied here, for example in HTML code.CComment
. A comment in form<!--something-->
. It is not affected by symbol replacement.CElement
. A tag. It has three properties:m_Text
(the tag name),AttributeMap
(A string map atname -> at value), and by inheritance aCList
of Nodes.
Then, only a CElement
node type should have
children.
CXXMLFile Class Reference
List of all members.Public Methods
CXXMLFile () Constructor. virtual ~CXXMLFile () void RemoveAll () void AddSymbol (CString coded, CString decoded) void DefaultSymbols () void ClearSymbols () void AddOpenTag (CString tag) bool Write () CString GetFile () void SetFile (CString filename) bool Read ()
|
CElementPart * Root () Gets the root. (Create one if it's empty). 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)
|
Public Attributes
CStringList m_ErrorList |
Private Methods
void Decodify (CString &html) Decodify using symbol table. void Codify (CString &html) |
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("<","<"); AddSymbol(">",">"); AddSymbol(""","\""); AddSymbol(" "," "); AddSymbol("'","'"); AddSymbol("&","&"); 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); } } }