Click here to Skip to main content
15,889,200 members
Articles / Mobile Apps / Windows Mobile
Article

XMLite: simple XML parser.

Rate me:
Please Sign up or sign in to vote.
4.65/5 (48 votes)
11 Oct 2004CPOL3 min read 733K   15.6K   132   192
Easy to access and simple XML parser

Sample Image - XMLite1.gif

Why XMLite?

In my previous project, I needed some simple XML parser. I worked with Jabber server. Because I had no time I worked with Jabber client library called Jabbercom, a Win32 COM based DLL module. Jabber protocol is based on XML. But that library was not a complete XML parser for my project.

First, it couldn't support Korean text (maybe other languages too) and there is no escape character processing, and no entity encode/decode supports. I had to replace XML parser engine, but I can't use MSXML and Expat, and it had a heavy installation or was hard to use. So I decided to make XMLite. It is not a fully supported XML parser, but it is simple and small, so I hope it helps someone.

Using XMLite

Simply, XMLite has two main data structures, XNode and XAttr. XNode is for XML element node and XAttr is for XML attribute node. XNode has child XNodes and own attributes list XAttrs. If you see my source code, you'll think code is so easy to understand and use. The code is simple.

  1. XML parsing

    XMLite can parse one XML tag node plain text like below. You can check for parsing error. If XNode::Load returns NULL, then simply you can know plain XML text has some error. If you want to know more error information, then go to section 4 - error handling.

    CString sxml;
    sxml = _T("\
    <TAddress desc='book of bro'>\
    <TPerson type='me'><Name>Cho,Kyung Min</Name><Nick>bro</Nick></TPerson>\
    <TPerson type='friend'><Name>Baik,Ji Hoon</Name><Nick>bjh</Nick></TPerson>\
    <TPerson type=friend><Name>Bak,Gun Joo</Name><Nick>dichter</Nick></TPerson>\
    <TInformation count='3'/>\
    </TAddress>");
    
    XNode xml;
    if( xml.Load( sxml ) )
        AfxMessageBox(xml.GetXML());
    else
        AfxMessageBox(_T("error")); // simple parsing error check

    The result is shown in the picture above.

  2. Traveling with parsed XML

    CString sxml;
    sxml = _T("\
    <TAddressBook description=\"book of bro\">\
    <TPerson type='me'><Name>Cho,Kyung Min</Name><Nick>bro</Nick></TPerson>\
    <TPerson type='friend'><Name>Baik,Ji Hoon</Name><Nick>bjh</Nick></TPerson>\
    <TPerson type=friend><Name>Bak,Gun Joo</Name><Nick>dichter</Nick></TPerson>\
    <TInformation count='3'/>\
    </TAddressBook>");
    
    XNode xml;
    xml.Load( sxml );
    
    int i;
    XNodes childs;
    
    // DOM tree Childs Traveling 
    // method 1: Using GetChildCount() and GetChild()
    // Result: Person, Person, Person, Information
    LPXNode child;
    for( i = 0 ; i < xml.GetChildCount(); i++)
    {
        child = xml.GetChild(i);
        AfxMessageBox( child->GetXML() );
    }
    
    // method 2: LPXNodes and GetChilds() ( same result with method 1 )
    // Result: Person, Person, Person, Information
    childs = xml.GetChilds();
    for( i = 0 ; i < childs.size(); i++)
        AfxMessageBox( childs[i]->GetXML() );
    
    // method 3: Selected Childs with GetChilds()
    // Result: Person, Person, Person
    childs = xml.GetChilds(_T("Person") );
    for( i = 0 ; i < childs.size(); i++)
    {
        AfxMessageBox( childs[i]->GetXML() );
    }
    
    // method 4: Get Attribute Vaule of Child
    // Result: 3
    AfxMessageBox( xml.GetChildAttrValue( _T("Information"), _T("count") ) );
    int count = XStr2Int( xml.GetChildAttrValue( _T("Information"), 
                                                         _T("count") ));
    ASSERT( count == 3 );
  3. DOM Modify

    CString sxml;
    sxml = _T("\
    <TAddressBook description=\"book of bro\">\
    <TPerson type='me'><Name>Cho,Kyung Min</Name><Nick>bro</Nick></TPerson>\
    <TPerson type='friend'><Name>Baik,Ji Hoon</Name><Nick>bjh</Nick></TPerson>\
    <TPerson type=friend><Name>Bak,Gun Joo</Name><Nick>dichter</Nick></TPerson>\
    <TInformation count='3'/>\
    </TAddressBook>");
    
    XNode xml;
    xml.Load( sxml );
    
    // remove 'bro node'
    LPXNode child_bro = xml.GetChild(0);
    xml.RemoveChild( child_bro );
    
    AfxMessageBox(xml.GetXML());

    Result: there is no bro node.

    XML
    <TAddressBook description='book of bro' >
        <TPerson type='friend' >
            <Name>Baik,Ji Hoon</Name>
            <Nick>bjh</Nick>
        </TPerson>
        <TPerson type='friend' >
            <Name>Bak,Gun Joo</Name>
            <Nick>dichter</Nick>
        </TPerson>
        <TInformation count='3' />
    </TAddressBook>
  4. Error Handling

    XMLite has xml error handling, but it's not complete.

    CString serror_xml;
    serror_xml = _T("<XML>\
    <NoCloseTag type='me'><Name>Cho,Kyung Min</Name><Nick>bro</Nick>\
    </XML>");
        
    XNode xml;
    PARSEINFO pi;
    xml.Load( serror_xml, &pi );
    
    if( pi.erorr_occur ) // is error_occur?
    {
        //result: '<NoCloseTag> ... </XML>' is not wel-formed.
        AfxMessageBox( pi.error_string );
        AfxMessageBox( xml.GetXML()  );
    }
    else
        ASSERT(FALSE);

    then, result is

    '<NoCloseTag> ... </XML>' is not wel-formed.
  5. Entity and Escape Char Test

    XMLite has escape process. But this updated version has no escape for general case. But still you can use escape character with parsing value.

    pi.escape_value = '\\' 

    Upper case, escape character is:

    '\'
    like C/C++. And it has entity processing. Entity table is like shown below:
    Special characterSpecial meaningEntity encoding
    >Begins a tag.>
    <Ends a tag.<
    "Quotation mark."
    'Apostrophe.&apos;
    &Ampersand.&
    CString sxml;
    sxml = _T("<XML>\
    <TAG attr='<\\'asdf\\\">'>asdf</TAG>\
    </XML>");
    
    XNode xml;
    PARSEINFO pi;
    pi.escape_value = '\\'  // using escape character on value string
    xml.Load( sxml, &pi );
    
    AfxMessageBox( xml.GetXML()  );

    Result:

    XML
    <XML>
        <TAG attr='<&apos;asdf">' >asdf</TAG>
    </XML>
  6. Configurate Parse and Display

    XMLite can trim when parsing and add newline for display (default).

    CString sxml;
    sxml = _T("<XML>\
    <TAG attr='   qwer      '>        asdf       </TAG>\
    </XML>");
    
    XNode xml;
    
    xml.Load( sxml );
    AfxMessageBox( xml.GetXML()  );
    
    PARSEINFO pi;
    pi.trim_value = true; // trim value
    xml.Load( sxml, &pi );
    AfxMessageBox( xml.GetXML()  );
    
    DISP_OPT opt;
    opt.newline = false; // no new line
    
    AfxMessageBox( xml.GetXML( &opt )  );

    Result:

    first,

    XML
    <XML>
        <TAG attr='   qwer      ' >        asdf       </TAG>
    </XML>

    after,

    <XML><TAG attr='qwer' >asdf</TAG></XML>
  7. Custom entity table

    XMLite can customize entity table for special parsing and display. You can define new entity table for customized parsing.

    CString sxml;
    sxml = _T("<XML>\
    <TAG attr='&asdf>'></TAG>\
    </XML>");
    
    // customized entity list
    static const XENTITY entity_table[] = {
            { '<', _T("<"), 4 } ,
            { '&', _T("&"), 5 }
        };
    XENTITYS entitys( (LPXENTITY)entity_table, 2 ) ;
    
    PARSEINFO pi;
    XNode xml;
    pi.entity_value = true; // force to use custom entitys
    pi.entitys = &entitys;
    xml.Load( sxml, &pi );
    AfxMessageBox( xml.GetXML()  );
    
    DISP_OPT opt;
    opt.entitys = &entitys;
    opt.reference_value = true; // force to use custom entitys
    
    AfxMessageBox( xml.GetXML( &opt )  );
  8. branch copy (deep-copy)

    Now XMLite can copy branch.

    void CTestXMLiteDlg::OnButton9() 
    {
        // TODO: Add your control notification handler code here
        CString sxml;
        sxml = _T("<addressbook description=""\"</span>book"" />\
    <person type=""me"" /><NAME>Cho,Kyung Min</NAME><NICK>bro</NICK></person />\
    <person type=""friend"" /><NAME>Baik,Ji Hoon</NAME><NICK>bjh</NICK></person />\
    <person type=""friend"" /><NAME>Bak,Gun Joo</NAME><NICK>dichter</NICK></person />\
    <information count=""3"" />\
    </addressbook />");
    
        XNode xml;
        xml.Load( sxml );
        AfxMessageBox( xml.GetXML()  );
    
            // copy one level node with its own attributes
        XNode xml2;
        xml2.CopyNode( &xml );
        AfxMessageBox( xml2.GetXML()  );
           
            // copy branch of other node (deep-copy)
        XNode xml3;
        //same with xml3 = xml;
        xml3.CopyBranch( &xml );
        AfxMessageBox( xml3.GetXML()  );
    
            // append copied-branch of other node as my child
        XNode xml4;
        //same with xml3.CopyBranch( &xml );
        xml4.AppendChildBranch( &xml );
        AfxMessageBox( xml4.GetXML()  );
    }
  9. Parsing xml with PI/CDATA/Comment

    Now XMLite can parse with PI/CDATA/Comment. But Still XMLite doesn't support PI's encoding function.

    void CTestXMLiteDlg::OnButton10() 
    {
     // TODO: Add your control notification handler code here
     CString sxml;
     sxml = _T("<?xml version='1.0'?>\
    \
    <![CDATA[some data]]>\
    <a>\
     <![CDATA[some data]]>\
     value\
     <![CDATA[some data2]]>\
    </a><!-- comment2-->");
     
     XNode xml;
     xml.Load( sxml );
    
     AfxMessageBox( xml.GetXML()  );
    }
  10. Parsing un-welformed xml (like HTML)

    Now XMLite can parse un-welformed xml like HTML with 'force_parse' attribute

    void CTestXMLiteDlg::OnButton11() 
    {
     // TODO: Add your control notification handler code here
     CString sXML = "\
    < html>\
      < body width='100'>\
         Some times I got say...\
      \
      \
      < p>\
      Thanks\
      < /body>\
    < /html>";
    
     XDoc xml;
    
     PARSEINFO pi;
     pi.force_parse = true;
     if( xml.Load( sXML, &pi ) )
     {
      LPXNode root = xml.GetRoot();
      //root->AppendChild( _T("child"), _T("value") );
      AfxMessageBox( xml.GetXML() );
     }
    
     // you can't not parse without force_parse on un-welformed xml!
     XNode node;
     if( node.Load( sXML ) )
     {
      AfxMessageBox( node.GetXML() );
     } 
    }
  11. Deep-Find

    XMLite's node can search own all children with tag name.

    CString sXML = "\
    <a>\
     
      \
     
      <C/>\
     
      <D/>\
     
      \
    </a>";
    
     XNode node;
     if( node.Load( sXML ) )
     {
      AfxMessageBox( node.GetXML() );
    
      LPXNode found = NULL;
      found = node.Find( _T("D") );
      if( found )
      {
       AfxMessageBox( found->GetXML() );
      }
     }

History

// XMLite : XML Lite Parser Library
// by bro ( Cho,Kyung Min: bro@shinbiro.com ) 2002-10-30
// History.
// 2002-10-29 : First Coded. Parsing XMLElelement and Attributes.
//              get xml parsed string ( looks good )
// 2002-10-30 : Get Node Functions, error handling ( not completed )
// 2002-12-06 : Helper Funtion string to long
// 2002-12-12 : Entity Helper Support
// 2003-04-08 : Close,
// 2003-07-23 : add property escape_value. (now no escape on default)
// 2003-10-24 : bugfix) attribute parsing <TAG \r\n a="1" /> is now ok
// 2004-03-05 : add branch copy functions

License

Sometimes I get email about license of XMLite. You can use/modify/redistribute XMLite for commercial/noncomercial. But please give me thanks email with your project information.
Then I will be happy and add it to references of XMLite. If you fix or update XMLite then give it to me for all to have. Thanks.

Reference

License

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


Written By
Software Developer
Korea (Republic of) Korea (Republic of)
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
AnswerRe: gnu gcc version of this? Pin
infosarang27-Mar-09 1:18
infosarang27-Mar-09 1:18 
AnswerRe: gnu gcc version of this? Pin
Cho, Kyung-min17-Aug-09 20:20
Cho, Kyung-min17-Aug-09 20:20 
Generalnice, but. Pin
malleor13-Mar-09 5:27
malleor13-Mar-09 5:27 
GeneralRe: nice, but. but but but. Pin
malleor13-Mar-09 7:08
malleor13-Mar-09 7:08 
GeneralThanks a lot! Pin
snowtiger912712-Mar-09 20:15
snowtiger912712-Mar-09 20:15 
QuestionXMLite not compiled in VC++ 2005 Pin
infosarang22-Feb-09 22:24
infosarang22-Feb-09 22:24 
AnswerRe: XMLite not compiled in VC++ 2005 Pin
infosarang22-Feb-09 22:54
infosarang22-Feb-09 22:54 
GeneralRe: XMLite not compiled in VC++ 2005 Pin
Sadru11-Feb-10 19:03
Sadru11-Feb-10 19:03 
//following version is edited to work for VC++ 2008 and also Unicode implemented

// XMLite.cpp: implementation of the XMLite class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "XMLite.h"
#include &lt;iostream&gt;
#include &lt;sstream&gt;
#include &lt;string&gt;

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

static const TCHAR chXMLTagOpen = '&lt;';
static const TCHAR chXMLTagClose = '&gt;';
static const TCHAR chXMLTagPre = '/';
static const TCHAR chXMLEscape = '\\'; // for value field escape

static const TCHAR szXMLPIOpen[] = _T("&lt;?");
static const TCHAR szXMLPIClose[] = _T("?&gt;");
static const TCHAR szXMLCommentOpen[] = _T("&lt;!--");
static const TCHAR szXMLCommentClose[] = _T("--&gt;");
static const TCHAR szXMLCDATAOpen[] = _T("&lt;![CDATA[");
static const TCHAR szXMLCDATAClose[] = _T("]]&gt;");

static const XENTITY x_EntityTable[] = {
{ '&amp;', _T("&amp;amp;"), 5 } ,
{ '\"', _T("&amp;quot;"), 6 } ,
{ '\'', _T("&amp;apos;"), 6 } ,
{ '&lt;', _T("&amp;lt;"), 4 } ,
{ '&gt;', _T("&amp;gt;"), 4 }
};

PARSEINFO piDefault;
DISP_OPT optDefault;
XENTITYS entityDefault((LPXENTITY)x_EntityTable, sizeof(x_EntityTable)/sizeof(x_EntityTable[0]) );
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////


//========================================================
// Name : _tcschrs
// Desc : same with _tcspbrk
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPTSTR _tcschrs( LPCTSTR psz, LPCTSTR pszchs )
{
while( psz &amp;&amp; *psz )
{
if( wcschr( pszchs, *psz ) )
return (LPTSTR)psz;
psz++;
}
return NULL;
}

//========================================================
// Name : _tcsskip
// Desc : skip space
// Param :
// Return : skiped string
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPTSTR _tcsskip( LPCTSTR psz )
{
//while( psz &amp;&amp; *psz == ' ' &amp;&amp; *psz == 13 &amp;&amp; *psz == 10 ) psz++;
while( psz &amp;&amp; isspace(*psz) ) psz++;

return (LPTSTR)psz;
}

//========================================================
// Name : _tcsechr
// Desc : similar with _tcschr with escape process
// Param : escape - will be escape character
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPTSTR _tcsechr( LPCTSTR psz, int ch, int escape )
{
LPTSTR pch = (LPTSTR)psz;

while( pch &amp;&amp; *pch )
{
if( escape != 0 &amp;&amp; *pch == escape )
pch++;
else
if( *pch == ch )
return (LPTSTR)pch;
pch++;
}
return pch;
}

//========================================================
// Name : _tcselen
// Desc : similar with _tcslen with escape process
// Param : escape - will be escape character
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
int _tcselen( int escape, LPTSTR srt, LPTSTR end = NULL )
{
int len = 0;
LPTSTR pch = srt;
if( end==NULL ) end = (LPTSTR)sizeof(long);
LPTSTR prev_escape = NULL;
while( pch &amp;&amp; *pch &amp;&amp; pch&lt;end )
{
if( escape != 0 &amp;&amp; *pch == escape &amp;&amp; prev_escape == NULL )
prev_escape = pch;
else
{
prev_escape = NULL;
len++;
}
pch++;
}
return len;
}

//========================================================
// Name : _tcsecpy
// Desc : similar with _tcscpy with escape process
// Param : escape - will be escape character
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
void _tcsecpy( LPTSTR psz, int escape, LPTSTR srt, LPTSTR end = NULL )
{
LPTSTR pch = srt;
if( end==NULL ) end = (LPTSTR)sizeof(long);
LPTSTR prev_escape = NULL;
while( pch &amp;&amp; *pch &amp;&amp; pch&lt;end )
{
if( escape != 0 &amp;&amp; *pch == escape &amp;&amp; prev_escape == NULL )
prev_escape = pch;
else
{
prev_escape = NULL;
*psz++ = *pch;
}

pch++;
}

*psz = '\0';
}

//========================================================
// Name : _tcsepbrk
// Desc : similar with _tcspbrk with escape process
// Param : escape - will be escape character
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPTSTR _tcsepbrk( LPCTSTR psz, LPCTSTR chset, int escape )
{
LPTSTR pch = (LPTSTR)psz;
LPTSTR prev_escape = NULL;
while( pch &amp;&amp; *pch )
{
if( escape != 0 &amp;&amp; *pch == escape &amp;&amp; prev_escape == NULL )
prev_escape = pch;
else
{
prev_escape = NULL;
if( _tcschr( chset, *pch ) )
return (LPTSTR)pch;
}
pch++;
}
return pch;
}

//========================================================
// Name : _tcsenicmp
// Desc : similar with _tcsnicmp with escape process
// Param : escape - will be escape character
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
int _tcsenicmp( LPCTSTR psz, LPCTSTR str, int len, int escape )
{
LPTSTR pch = (LPTSTR)psz;
LPTSTR prev_escape = NULL;
LPTSTR des = (LPTSTR)str;
int i = 0;

while( pch &amp;&amp; *pch &amp;&amp; i &lt; len )
{
if( escape != 0 &amp;&amp; *pch == escape &amp;&amp; prev_escape == NULL )
prev_escape = pch;
else
{
prev_escape = NULL;
if( tolower(*pch) != tolower(des[i]) )
break;
i++;
}
pch ++;
}

// find
if( i == len )
return 0;
if( psz[i] &gt; des[i] )
return 1;
return -1;
}

//========================================================
// Name : _tcsenistr
// Desc : similar with _tcsistr with escape process
// Param : escape - will be escape character
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPTSTR _tcsenistr( LPCTSTR psz, LPCTSTR str, int len, int escape )
{
LPTSTR pch = (LPTSTR)psz;
LPTSTR prev_escape = NULL;
LPTSTR des = (LPTSTR)str;
int i = 0;

while( pch &amp;&amp; *pch )
{
if( escape != 0 &amp;&amp; *pch == escape &amp;&amp; prev_escape == NULL )
prev_escape = pch;
else
{
prev_escape = NULL;
if( _tcsenicmp( pch, str, len, escape ) == 0 )
return (LPTSTR)pch;
}
pch++;
}
return pch;
}

//========================================================
// Name : _tcseistr
// Desc : similar with _tcsistr with escape process
// Param : escape - will be escape character
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPTSTR _tcseistr( LPCTSTR psz, LPCTSTR str, int escape )
{
int len = _tcslen( str );
return _tcsenistr( psz, str, len, escape );
}

//========================================================
// Name : _SetString
// Desc : put string of (psz~end) on ps string
// Param : trim - will be trim?
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
void _SetString( LPTSTR psz, LPTSTR end, CString* ps, bool trim = FALSE, int escape = 0 )
{
//trim
if( trim )
{
while( psz &amp;&amp; psz &lt; end &amp;&amp; _istspace(*psz) ) psz++;
while( (end-1) &amp;&amp; psz &lt; (end-1) &amp;&amp; _istspace(*(end-1)) ) end--;
}
int len = end - psz;
if( len &lt;= 0 ) return;
if( escape )
{
len = _tcselen( escape, psz, end );
LPTSTR pss = ps-&gt;GetBufferSetLength( len );
_tcsecpy( pss, escape, psz, end );
}
else
{
LPTSTR pss = ps-&gt;GetBufferSetLength(len + 1 );
memcpy( pss, psz, len * sizeof(TCHAR) );
pss[len] = '\0';
}
}

_tagXMLNode::~_tagXMLNode()
{
Close();
}

void _tagXMLNode::Close()
{
int i;
for( i = 0 ; i &lt; (int)childs.size(); i ++)
{
LPXNode p = childs[i];
if( p )
{
delete p; childs[i] = NULL;
}
}
childs.clear();

for( i = 0 ; i &lt; (int)attrs.size(); i ++)
{
LPXAttr p = attrs[i];
if( p )
{
delete p; attrs[i] = NULL;
}
}
attrs.clear();
}

// attr1="value1" attr2='value2' attr3=value3 /&gt;
// ^- return pointer
//========================================================
// Name : LoadAttributes
// Desc : loading attribute plain xml text
// Param : pszAttrs - xml of attributes
// pi = parser information
// Return : advanced string pointer. (error return NULL)
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPTSTR _tagXMLNode::LoadAttributes( LPCTSTR pszAttrs , LPPARSEINFO pi /*= &amp;piDefault*/)
{
LPTSTR xml = (LPTSTR)pszAttrs;

while( xml &amp;&amp; *xml )
{
if( xml = _tcsskip( xml ) )
{
// close tag
if( *xml == chXMLTagClose || *xml == chXMLTagPre )
// wel-formed tag
return xml;

// XML Attr Name
TCHAR* pEnd = _tcspbrk( xml, L" =" );
if( pEnd == NULL )
{
// error
if( pi-&gt;erorr_occur == false )
{
pi-&gt;erorr_occur = true;
pi-&gt;error_pointer = xml;
pi-&gt;error_code = PIE_ATTR_NO_VALUE;
pi-&gt;error_string.Format( _T("&lt;%s&gt; attribute has error "), name );
}
return NULL;
}

LPXAttr attr = new XAttr;
attr-&gt;parent = this;

// XML Attr Name
_SetString( xml, pEnd, &amp;attr-&gt;name );

// add new attribute
attrs.push_back( attr );
xml = pEnd;

// XML Attr Value
if( xml = _tcsskip( xml ) )
{
//if( xml = _tcschr( xml, '=' ) )
if( *xml == '=' )
{
if( xml = _tcsskip( ++xml ) )
{
// if " or '
// or none quote
int quote = *xml;
if( quote == '"' || quote == '\'' )
pEnd = _tcsechr( ++xml, quote, chXMLEscape );
else
{
//attr= value&gt;
// none quote mode
//pEnd = _tcsechr( xml, ' ', '\\' );
pEnd = _tcsepbrk( xml, _T(" &gt;"), chXMLEscape );
}

bool trim = pi-&gt;trim_value;
TCHAR escape = pi-&gt;escape_value;
//_SetString( xml, pEnd, &amp;attr-&gt;value, trim, chXMLEscape );
_SetString( xml, pEnd, &amp;attr-&gt;value, trim, escape );
xml = pEnd;
// ATTRVALUE
if( pi-&gt;entity_value &amp;&amp; pi-&gt;entitys )
attr-&gt;value = pi-&gt;entitys-&gt;Ref2Entity(attr-&gt;value);

if( quote == '"' || quote == '\'' )
xml++;
}
}
}
}
}

// not wel-formed tag
return NULL;
}

// attr1="value1" attr2='value2' attr3=value3 /&gt;
// ^- return pointer
//========================================================
// Name : LoadAttributes
// Desc : loading attribute plain xml text
// Param : pszAttrs - xml of attributes
// pszEnd - last string
// pi = parser information
// Return : advanced string pointer. (error return NULL)
//--------------------------------------------------------
// Coder Date Desc
// bro 2004-06-14
//========================================================
LPTSTR _tagXMLNode::LoadAttributes( LPCTSTR pszAttrs, LPCTSTR pszEnd, LPPARSEINFO pi /*= &amp;piDefault*/ )
{
LPTSTR xml = (LPTSTR)pszAttrs;

while( xml &amp;&amp; *xml )
{
if( xml = _tcsskip( xml ) )
{
// close tag
if( xml &gt;= pszEnd )
// wel-formed tag
return xml;

// XML Attr Name
TCHAR* pEnd = _tcspbrk( xml, L" =" );
if( pEnd == NULL )
{
// error
if( pi-&gt;erorr_occur == false )
{
pi-&gt;erorr_occur = true;
pi-&gt;error_pointer = xml;
pi-&gt;error_code = PIE_ATTR_NO_VALUE;
pi-&gt;error_string.Format( _T("&lt;%s&gt; attribute has error "), name );
}
return NULL;
}

LPXAttr attr = new XAttr;
attr-&gt;parent = this;

// XML Attr Name
_SetString( xml, pEnd, &amp;attr-&gt;name );

// add new attribute
attrs.push_back( attr );
xml = pEnd;

// XML Attr Value
if( xml = _tcsskip( xml ) )
{
//if( xml = _tcschr( xml, '=' ) )
if( *xml == '=' )
{
if( xml = _tcsskip( ++xml ) )
{
// if " or '
// or none quote
int quote = *xml;
if( quote == '"' || quote == '\'' )
pEnd = _tcsechr( ++xml, quote, chXMLEscape );
else
{
//attr= value&gt;
// none quote mode
//pEnd = _tcsechr( xml, ' ', '\\' );
pEnd = _tcsepbrk( xml, _T(" &gt;"), chXMLEscape );
}

bool trim = pi-&gt;trim_value;
TCHAR escape = pi-&gt;escape_value;
//_SetString( xml, pEnd, &amp;attr-&gt;value, trim, chXMLEscape );
_SetString( xml, pEnd, &amp;attr-&gt;value, trim, escape );
xml = pEnd;
// ATTRVALUE
if( pi-&gt;entity_value &amp;&amp; pi-&gt;entitys )
attr-&gt;value = pi-&gt;entitys-&gt;Ref2Entity(attr-&gt;value);

if( quote == '"' || quote == '\'' )
xml++;
}
}
}
}
}

// not wel-formed tag
return NULL;
}

// &lt;?xml version="1.0"?&gt;
// ^- return pointer
//========================================================
// Name : LoadProcessingInstrunction
// Desc : loading processing instruction
// Param : pszXml - PI string
// pi - parser information
// Return : advanced string pointer. (error return NULL)
//--------------------------------------------------------
// Coder Date Desc
// bro 2004-06-14
//========================================================
LPTSTR _tagXMLNode::LoadProcessingInstrunction( LPCTSTR pszXml, LPPARSEINFO pi /*= &amp;piDefault*/ )
{
// find the end of pi
LPTSTR end = _tcsenistr( pszXml, szXMLPIClose, sizeof(szXMLPIClose)/sizeof(TCHAR)-1, pi ? pi-&gt;escape_value : 0 );
if( end == NULL )
return NULL;

// process pi
if( doc )
{
LPTSTR xml = (LPTSTR)pszXml;

LPXNode node = new XNode;
node-&gt;parent = this;
node-&gt;doc = doc;
node-&gt;type = XNODE_PI;

xml += sizeof(szXMLPIOpen)/sizeof(TCHAR)-1;
TCHAR* pTagEnd = _tcspbrk( xml, L" ?&gt;" );
_SetString( xml, pTagEnd, &amp;node-&gt;name );
xml = pTagEnd;

node-&gt;LoadAttributes( xml, end, pi );

doc-&gt;childs.push_back( node );
}

end += sizeof(szXMLPIClose)/sizeof(TCHAR)-1;
return end;
}

// &lt;!-- comment --&gt;
// ^- return pointer
//========================================================
// Name : LoadComment
// Desc : loading comment
// Param : pszXml - comment string
// pi - parser information
// Return : advanced string pointer. (error return NULL)
//--------------------------------------------------------
// Coder Date Desc
// bro 2004-06-14
//========================================================
LPTSTR _tagXMLNode::LoadComment( LPCTSTR pszXml, LPPARSEINFO pi /*= &amp;piDefault*/ )
{
// find the end of comment
LPTSTR end = _tcsenistr( pszXml, szXMLCommentClose, sizeof(szXMLCommentClose)/sizeof(TCHAR)-1, pi ? pi-&gt;escape_value : 0 );
if( end == NULL )
return NULL;

// process comment
LPXNode par = parent;
if( parent == NULL &amp;&amp; doc )
par = (LPXNode)&amp;doc;
if( par )
{
LPTSTR xml = (LPTSTR)pszXml;
xml += sizeof(szXMLCommentOpen)/sizeof(TCHAR)-1;

LPXNode node = new XNode;
node-&gt;parent = this;
node-&gt;doc = doc;
node-&gt;type = XNODE_COMMENT;
node-&gt;name = _T("#COMMENT");
_SetString( xml, end, &amp;node-&gt;value, FALSE );

par-&gt;childs.push_back( node );
}

end += sizeof(szXMLCommentClose)/sizeof(TCHAR)-1;
return end;
}

// &lt;![CDATA[ cdata ]]&gt;
// ^- return pointer
//========================================================
// Name : LoadCDATA
// Desc : loading CDATA
// Param : pszXml - CDATA string
// pi - parser information
// Return : advanced string pointer. (error return NULL)
//--------------------------------------------------------
// Coder Date Desc
// bro 2004-06-14
//========================================================
LPTSTR _tagXMLNode::LoadCDATA( LPCTSTR pszXml, LPPARSEINFO pi /*= &amp;piDefault*/ )
{
// find the end of CDATA
LPTSTR end = _tcsenistr( pszXml, szXMLCDATAClose, sizeof(szXMLCDATAClose)/sizeof(TCHAR)-1, pi ? pi-&gt;escape_value : 0 );
if( end == NULL )
return NULL;

// process CDATA
LPXNode par = parent;
if( parent == NULL &amp;&amp; doc )
par = (LPXNode)&amp;doc;
if( par )
{
LPTSTR xml = (LPTSTR)pszXml;
xml += sizeof(szXMLCDATAOpen)/sizeof(TCHAR)-1;

LPXNode node = new XNode;
node-&gt;parent = this;
node-&gt;doc = doc;
node-&gt;type = XNODE_CDATA;
node-&gt;name = _T("#CDATA");
_SetString( xml, end, &amp;node-&gt;value, FALSE );

par-&gt;childs.push_back( node );
}

end += sizeof(szXMLCDATAClose)/sizeof(TCHAR)-1;
return end;
}

//========================================================
// Name : LoadOtherNodes
// Desc : internal function for loading PI/CDATA/Comment
// Param : node - current xml node
// pbRet - error occur
// pszXml - CDATA string
// pi - parser information
// Return : advanced string pointer. (error return NULL)
//--------------------------------------------------------
// Coder Date Desc
// bro 2004-06-14
//========================================================
LPTSTR LoadOtherNodes( LPXNode node, bool* pbRet, LPCTSTR pszXml, LPPARSEINFO pi /*= &amp;piDefault*/ )
{
LPTSTR xml = (LPTSTR)pszXml;
bool do_other_type = true;
*pbRet = false;

while( xml &amp;&amp; do_other_type )
{
do_other_type = false;

xml = _tcsskip( xml );
LPTSTR prev = xml;
// is PI( Processing Instruction ) Node?
if( _tcsnicmp( xml, szXMLPIOpen, sizeof(szXMLPIOpen)/sizeof(TCHAR)-1 ) == 0 )
{
// processing instrunction parse
// return pointer is next node of pi
xml = node-&gt;LoadProcessingInstrunction( xml, pi );
//if( xml == NULL )
// return NULL;
// restart xml parse
}

if( xml != prev )
do_other_type = true;
xml = _tcsskip( xml );
prev = xml;

// is comment Node?
if( _tcsnicmp( xml, szXMLCommentOpen, sizeof(szXMLCommentOpen)/sizeof(TCHAR)-1 ) == 0 )
{
// processing comment parse
// return pointer is next node of comment
xml = node-&gt;LoadComment( xml, pi );
// comment node is terminal node
if( node-&gt;parent &amp;&amp; node-&gt;parent-&gt;type != XNODE_DOC
&amp;&amp; xml != prev )
{
*pbRet = true;
return xml;
}
// restart xml parse when this node is root doc node
}

if( xml != prev )
do_other_type = true;

xml = _tcsskip( xml );
prev = xml;
// is CDATA Node?
if( _tcsnicmp( xml, szXMLCDATAOpen, sizeof(szXMLCDATAOpen)/sizeof(TCHAR)-1 ) == 0 )
{
// processing CDATA parse
// return pointer is next node of CDATA
xml = node-&gt;LoadCDATA( xml, pi );
// CDATA node is terminal node
if( node-&gt;parent &amp;&amp; node-&gt;parent-&gt;type != XNODE_DOC
&amp;&amp; xml != prev )
{
*pbRet = true;
return xml;
}
// restart xml parse when this node is root doc node
}

if( xml != prev )
do_other_type = true;
}

return xml;
}

// &lt;TAG attr1="value1" attr2='value2' attr3=value3 &gt;
// &lt;/TAG&gt;
// or
// &lt;TAG /&gt;
// ^- return pointer
//========================================================
// Name : Load
// Desc : load xml plain text
// Param : pszXml - plain xml text
// pi = parser information
// Return : advanced string pointer (error return NULL)
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPTSTR _tagXMLNode::Load( LPCTSTR pszXml, LPPARSEINFO pi /*= &amp;piDefault*/ )
{
// Close it
Close();

LPTSTR xml = (LPTSTR)pszXml;

xml = _tcschr( xml, chXMLTagOpen );
if( xml == NULL )
return NULL;

// Close Tag
if( *(xml+1) == chXMLTagPre ) // &lt;/Close
return xml;

// Load Other Node before &lt;Tag&gt;(pi, comment, CDATA etc)
bool bRet = false;
LPTSTR ret = NULL;
ret = LoadOtherNodes( this, &amp;bRet, xml, pi );
if( ret != NULL )
xml = ret;
if( bRet )
return xml;

// XML Node Tag Name Open
xml++;
TCHAR* pTagEnd = _tcspbrk( xml, L" /&gt;\t\r\n" );
_SetString( xml, pTagEnd, &amp;name );
xml = pTagEnd;
// Generate XML Attributte List
if( xml = LoadAttributes( xml, pi ) )
{
// alone tag &lt;TAG ... /&gt;
if( *xml == chXMLTagPre )
{
xml++;
if( *xml == chXMLTagClose )
// wel-formed tag
return ++xml;
else
{
// error: &lt;TAG ... / &gt;
if( pi-&gt;erorr_occur == false )
{
pi-&gt;erorr_occur = true;
pi-&gt;error_pointer = xml;
pi-&gt;error_code = PIE_ALONE_NOT_CLOSED;
pi-&gt;error_string = _T("Element must be closed.");
}
// not wel-formed tag
return NULL;
}
}
else
// open/close tag &lt;TAG ..&gt; ... &lt;/TAG&gt;
// ^- current pointer
{
// if text value is not exist, then assign value
//if( this-&gt;value.IsEmpty() || this-&gt;value == _T("") )
if( XIsEmptyString( value ) )
{
// Text Value
TCHAR* pEnd = _tcsechr( ++xml, chXMLTagOpen, chXMLEscape );
if( pEnd == NULL )
{
if( pi-&gt;erorr_occur == false )
{
pi-&gt;erorr_occur = true;
pi-&gt;error_pointer = xml;
pi-&gt;error_code = PIE_NOT_CLOSED;
pi-&gt;error_string.Format(_T("%s must be closed with &lt;/%s&gt;"), name );
}
// error cos not exist CloseTag &lt;/TAG&gt;
return NULL;
}

bool trim = pi-&gt;trim_value;
TCHAR escape = pi-&gt;escape_value;
//_SetString( xml, pEnd, &amp;value, trim, chXMLEscape );
_SetString( xml, pEnd, &amp;value, trim, escape );

xml = pEnd;
// TEXTVALUE reference
if( pi-&gt;entity_value &amp;&amp; pi-&gt;entitys )
value = pi-&gt;entitys-&gt;Ref2Entity(value);
}

// generate child nodes
while( xml &amp;&amp; *xml )
{
LPXNode node = new XNode;
node-&gt;parent = this;
node-&gt;doc = doc;
node-&gt;type = type;

xml = node-&gt;Load( xml,pi );
if( node-&gt;name.IsEmpty() == FALSE )
{
childs.push_back( node );

}
else
{
delete node;
}

// open/close tag &lt;TAG ..&gt; ... &lt;/TAG&gt;
// ^- current pointer
// CloseTag case
if( xml &amp;&amp; *xml &amp;&amp; *(xml+1) &amp;&amp; *xml == chXMLTagOpen &amp;&amp; *(xml+1) == chXMLTagPre )
{
// &lt;/Close&gt;
xml+=2; // C

if( xml = _tcsskip( xml ) )
{
CString closename;
TCHAR* pEnd = _tcspbrk( xml, L" &gt;" );
if( pEnd == NULL )
{
if( pi-&gt;erorr_occur == false )
{
pi-&gt;erorr_occur = true;
pi-&gt;error_pointer = xml;
pi-&gt;error_code = PIE_NOT_CLOSED;
pi-&gt;error_string.Format(_T("it must be closed with &lt;/%s&gt;"), name );
}
// error
return NULL;
}
_SetString( xml, pEnd, &amp;closename );
if( closename == this-&gt;name )
{
// wel-formed open/close
xml = pEnd+1;
// return '&gt;' or ' ' after pointer
return xml;
}
else
{
xml = pEnd+1;
// 2004.6.15 - example &lt;B&gt; alone tag
// now it can parse with attribute 'force_arse'
if( pi-&gt;force_parse == false )
{
// not welformed open/close
if( pi-&gt;erorr_occur == false )
{
pi-&gt;erorr_occur = true;
pi-&gt;error_pointer = xml;
pi-&gt;error_code = PIE_NOT_NESTED;
pi-&gt;error_string.Format(_T("'&lt;%s&gt; ... &lt;/%s&gt;' is not wel-formed."), name, closename );
}
return NULL;
}
}
}
}
else // Alone child Tag Loaded
// else ÇؾßÇÏ´ÂÁö ¸»¾Æ¾ßÇÏ´ÂÁö Àǽɰ£´Ù.
{

//if( xml &amp;&amp; this-&gt;value.IsEmpty() &amp;&amp; *xml !=chXMLTagOpen )
if( xml &amp;&amp; XIsEmptyString( value ) &amp;&amp; *xml !=chXMLTagOpen )
{
// Text Value
TCHAR* pEnd = _tcsechr( xml, chXMLTagOpen, chXMLEscape );
if( pEnd == NULL )
{
// error cos not exist CloseTag &lt;/TAG&gt;
if( pi-&gt;erorr_occur == false )
{
pi-&gt;erorr_occur = true;
pi-&gt;error_pointer = xml;
pi-&gt;error_code = PIE_NOT_CLOSED;
pi-&gt;error_string.Format(_T("it must be closed with &lt;/%s&gt;"), name );
}
return NULL;
}

bool trim = pi-&gt;trim_value;
TCHAR escape = pi-&gt;escape_value;
//_SetString( xml, pEnd, &amp;value, trim, chXMLEscape );
_SetString( xml, pEnd, &amp;value, trim, escape );

xml = pEnd;
//TEXTVALUE
if( pi-&gt;entity_value &amp;&amp; pi-&gt;entitys )
value = pi-&gt;entitys-&gt;Ref2Entity(value);
}
}
}
}
}

return xml;
}

// &lt;?xml version='1.0'?&gt;
// &lt;TAG attr1="value1" attr2='value2' attr3=value3 &gt;
// &lt;/TAG&gt;
// or
// &lt;TAG /&gt;
// ^- return pointer
//========================================================
// Name : Load
// Desc : load xml plain text for xml document
// Param : pszXml - plain xml text
// pi = parser information
// Return : advanced string pointer (error return NULL)
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPTSTR _tagXMLDocument::Load( LPCTSTR pszXml, LPPARSEINFO pi /*= NULL*/ )
{
LPXNode node = new XNode;
node-&gt;parent = (LPXNode)this;
node-&gt;type = XNODE_ELEMENT;
node-&gt;doc = this;
LPTSTR end;

if( pi == NULL )
pi = &amp;parse_info;

if( (end = node-&gt;Load( pszXml, pi )) == NULL )
{
delete node;
return NULL;
}

childs.push_back( node );

// Load Other Node after &lt;/Tag&gt;(pi, comment, CDATA etc)
LPTSTR ret;
bool bRet = false;
ret = LoadOtherNodes( node, &amp;bRet, end, pi );
if( ret != NULL )
end = ret;

return end;
}

LPXNode _tagXMLDocument::GetRoot()
{
XNodes::iterator it = childs.begin();
for( ; it != childs.end() ; ++(it) )
{
LPXNode node = *it;
if( node-&gt;type == XNODE_ELEMENT )
return node;
}
return NULL;
}

//========================================================
// Name : GetXML
// Desc : convert plain xml text from parsed xml attirbute
// Param :
// Return : converted plain string
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
CString _tagXMLAttr::GetXML( LPDISP_OPT opt /*= &amp;optDefault*/ )
{
std::basic_ostringstream&lt;TCHAR&gt; os;
//os &lt;&lt; (LPCTSTR)name &lt;&lt; "='" &lt;&lt; (LPCTSTR)value &lt;&lt; "' ";

os &lt;&lt; (LPCTSTR)name &lt;&lt; L"=" &lt;&lt; (char)opt-&gt;value_quotation_mark
&lt;&lt; (LPCTSTR)(opt-&gt;reference_value&amp;&amp;opt-&gt;entitys?opt-&gt;entitys-&gt;Entity2Ref(value):value)
&lt;&lt; (char)opt-&gt;value_quotation_mark &lt;&lt; L" ";
return os.str().c_str();
}

//========================================================
// Name : GetXML
// Desc : convert plain xml text from parsed xml node
// Param :
// Return : converted plain string
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
CString _tagXMLNode::GetXML( LPDISP_OPT opt /*= &amp;optDefault*/ )
{
std::basic_ostringstream&lt;TCHAR&gt; os;

// tab
if( opt &amp;&amp; opt-&gt;newline )
{
if( opt &amp;&amp; opt-&gt;newline )
os &lt;&lt; L"\r\n";
for( int i = 0 ; i &lt; opt-&gt;tab_base ; i++)
os &lt;&lt; '\t';
}

if( type == XNODE_DOC )
{
for( int i = 0 ; i &lt; (int)childs.size(); i++ )
os &lt;&lt; (LPCTSTR)childs[i]-&gt;GetXML( opt );
return os.str().c_str();
}
else
if( type == XNODE_PI )
{
// &lt;?TAG
os &lt;&lt; szXMLPIOpen &lt;&lt; (LPCTSTR)name;
// &lt;?TAG Attr1="Val1"
if( attrs.empty() == false ) os &lt;&lt; ' ';
for( int i = 0 ; i &lt; (int)attrs.size(); i++ )
{
os &lt;&lt; (LPCTSTR)attrs[i]-&gt;GetXML(opt);
}
//?&gt;
os &lt;&lt; szXMLPIClose;
return os.str().c_str();
}
else
if( type == XNODE_COMMENT )
{
// &lt;--comment
os &lt;&lt; szXMLCommentOpen &lt;&lt; (LPCTSTR)value;
//--&gt;
os &lt;&lt; szXMLCommentClose;
return os.str().c_str();
}
else
if( type == XNODE_CDATA )
{
// &lt;--comment
os &lt;&lt; szXMLCDATAOpen &lt;&lt; (LPCTSTR)value;
//--&gt;
os &lt;&lt; szXMLCDATAClose;
return os.str().c_str();
}

// &lt;TAG
os &lt;&lt; '&lt;' &lt;&lt; (LPCTSTR)name;

// &lt;TAG Attr1="Val1"
if( attrs.empty() == false ) os &lt;&lt; ' ';
for( int i = 0 ; i &lt; (int)attrs.size(); i++ )
{
os &lt;&lt; (LPCTSTR)attrs[i]-&gt;GetXML(opt);
}

if( childs.empty() &amp;&amp; value.IsEmpty() )
{
// &lt;TAG Attr1="Val1"/&gt; alone tag
os &lt;&lt; L"/&gt;";
}
else
{
// &lt;TAG Attr1="Val1"&gt; and get child
os &lt;&lt; '&gt;';
if( opt &amp;&amp; opt-&gt;newline &amp;&amp; !childs.empty() )
{
opt-&gt;tab_base++;
}

for( int i = 0 ; i &lt; (int)childs.size(); i++ )
os &lt;&lt; (LPCTSTR)childs[i]-&gt;GetXML( opt );

// Text Value
if( value != _T("") )
{
if( opt &amp;&amp; opt-&gt;newline &amp;&amp; !childs.empty() )
{
if( opt &amp;&amp; opt-&gt;newline )
os &lt;&lt; L"\r\n";
for( int i = 0 ; i &lt; opt-&gt;tab_base ; i++)
os &lt;&lt; '\t';
}
os &lt;&lt; (LPCTSTR)(opt-&gt;reference_value&amp;&amp;opt-&gt;entitys?opt-&gt;entitys-&gt;Entity2Ref(value):value);
}

// &lt;/TAG&gt; CloseTag
if( opt &amp;&amp; opt-&gt;newline &amp;&amp; !childs.empty() )
{
os &lt;&lt; L"\r\n";
for( int i = 0 ; i &lt; opt-&gt;tab_base-1 ; i++)
os &lt;&lt; '\t';
}
os &lt;&lt; L"&lt;/" &lt;&lt; (LPCTSTR)name &lt;&lt; '&gt;';

if( opt &amp;&amp; opt-&gt;newline )
{
if( !childs.empty() )
opt-&gt;tab_base--;
}
}

return os.str().c_str();
}

//========================================================
// ÇÔ¼ö¸í : GetText
// ¼³ ¸í : ³ëµå Çϳª¸¦ ÅؽºÆ® ¹®ÀÚ¿­·Î ¹Ýȯ
// ÀÎ ÀÚ :
// ¸®ÅÏ°ª : º¯È¯µÈ ¹®ÀÚ¿­
//--------------------------------------------------------
// ÀÛ¼ºÀÚ ÀÛ¼ºÀÏ ÀÛ¼ºÀÌÀ¯
// Á¶°æ¹Î 2004-06-15
//========================================================
CString _tagXMLNode::GetText( LPDISP_OPT opt /*= &amp;optDefault*/ )
{
std::basic_ostringstream&lt;TCHAR&gt; os;

if( type == XNODE_DOC )
{
for( int i = 0 ; i &lt; (int)childs.size(); i++ )
os &lt;&lt; (LPCTSTR)childs[i]-&gt;GetText( opt );
}
else
if( type == XNODE_PI )
{
// no text
}
else
if( type == XNODE_COMMENT )
{
// no text
}
else
if( type == XNODE_CDATA )
{
os &lt;&lt; (LPCTSTR)value;
}
else
if( type == XNODE_ELEMENT )
{
if( childs.empty() &amp;&amp; value.IsEmpty() )
{
// no text
}
else
{
// childs text
for( int i = 0 ; i &lt;(int) childs.size(); i++ )
os &lt;&lt; (LPCTSTR)childs[i]-&gt;GetText();

// Text Value
os &lt;&lt; (LPCTSTR)(opt-&gt;reference_value&amp;&amp;opt-&gt;entitys?opt-&gt;entitys-&gt;Entity2Ref(value):value);
}
}

return os.str().c_str();
}

//========================================================
// Name : GetAttr
// Desc : get attribute with attribute name
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXAttr _tagXMLNode::GetAttr( LPCTSTR attrname )
{
for( int i = 0 ; i &lt; (int)attrs.size(); i++ )
{
LPXAttr attr = attrs[i];
if( attr )
{
if( attr-&gt;name == attrname )
return attr;
}
}
return NULL;
}

//========================================================
// Name : GetAttrs
// Desc : find attributes with attribute name, return its list
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
XAttrs _tagXMLNode::GetAttrs( LPCTSTR name )
{
XAttrs attrs;
for( int i = 0 ; i &lt; (int)attrs.size(); i++ )
{
LPXAttr attr = attrs[i];
if( attr )
{
if( attr-&gt;name == name )
attrs.push_back( attr );
}
}
return attrs;
}

//========================================================
// Name : GetAttrValue
// Desc : get attribute with attribute name, return its value
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPCTSTR _tagXMLNode::GetAttrValue( LPCTSTR attrname )
{
LPXAttr attr = GetAttr( attrname );
return attr ? (LPCTSTR)attr-&gt;value : NULL;
}

XNodes _tagXMLNode::GetChilds()
{
return childs;
}

//========================================================
// Name : GetChilds
// Desc : Find childs with name and return childs list
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
XNodes _tagXMLNode::GetChilds( LPCTSTR name )
{
XNodes nodes;
for( int i = 0 ; i &lt; (int)childs.size(); i++ )
{
LPXNode node = childs[i];
if( node )
{
if( node-&gt;name == name )
nodes.push_back( node );
}
}
return nodes;
}

//========================================================
// Name : GetChild
// Desc : get child node with index
// Param :
// Return : NULL return if no child.
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXNode _tagXMLNode::GetChild( int i )
{
if( i &gt;= 0 &amp;&amp; i &lt;(int) childs.size() )
return childs[i];
return NULL;
}

//========================================================
// Name : GetChildCount
// Desc : get child node count
// Param :
// Return : 0 return if no child
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-12-26
//========================================================
int _tagXMLNode::GetChildCount()
{
return childs.size();
}

//========================================================
// Name : GetChild
// Desc : Find child with name and return child
// Param :
// Return : NULL return if no child.
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXNode _tagXMLNode::GetChild( LPCTSTR name )
{
for( int i = 0 ; i &lt; (int)childs.size(); i++ )
{
LPXNode node = childs[i];
if( node )
{
if( node-&gt;name == name )
return node;
}
}
return NULL;
}

//========================================================
// Name : GetChildValue
// Desc : Find child with name and return child's value
// Param :
// Return : NULL return if no child.
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPCTSTR _tagXMLNode::GetChildValue( LPCTSTR name )
{
LPXNode node = GetChild( name );
return (node != NULL)? (LPCTSTR)node-&gt;value : NULL;
}

CString _tagXMLNode::GetChildText( LPCTSTR name, LPDISP_OPT opt /*= &amp;optDefault*/ )
{
LPXNode node = GetChild( name );
return (node != NULL)? node-&gt;GetText(opt) : _T("");
}

LPXAttr _tagXMLNode::GetChildAttr( LPCTSTR name, LPCTSTR attrname )
{
LPXNode node = GetChild(name);
return node ? node-&gt;GetAttr(attrname) : NULL;
}

LPCTSTR _tagXMLNode::GetChildAttrValue( LPCTSTR name, LPCTSTR attrname )
{
LPXAttr attr = GetChildAttr( name, attrname );
return attr ? (LPCTSTR)attr-&gt;value : NULL;
}

//========================================================
// Name : Find
// Desc : find node with tag name from it's all childs
// Param :
// Return : NULL return if no found node.
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXNode _tagXMLNode::Find( LPCTSTR name )
{
XNodes::iterator it = childs.begin();
for( ; it != childs.end(); ++(it))
{
LPXNode child = *it;
if( child-&gt;name == name )
return child;

XNodes::iterator it = child-&gt;childs.begin();
for( ; it != child-&gt;childs.end(); ++(it))
{
LPXNode find = child-&gt;Find( name );
if( find != NULL )
return find;
}
}

return NULL;
}

//========================================================
// Name : GetChildIterator
// Desc : get child nodes iterator
// Param :
// Return : NULL return if no childs.
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
XNodes::iterator _tagXMLNode::GetChildIterator( LPXNode node )
{

XNodes::iterator it = childs.begin();
for( ; it != childs.end() ; ++(it) )
{
if( *it == node )
return it;
}
*it = NULL;
return it;
}

//========================================================
// Name : AppendChild
// Desc : add node
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXNode _tagXMLNode::AppendChild( LPCTSTR name /*= NULL*/, LPCTSTR value /*= NULL*/ )
{
return AppendChild( CreateNode( name, value ) );
}

//========================================================
// Name : AppendChild
// Desc : add node
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXNode _tagXMLNode::AppendChild( LPXNode node )
{
node-&gt;parent = this;
node-&gt;doc = doc;
childs.push_back( node );
return node;
}

//========================================================
// Name : RemoveChild
// Desc : detach node and delete object
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
bool _tagXMLNode::RemoveChild( LPXNode node )
{
XNodes::iterator it = GetChildIterator( node );
if( *it )
{
delete *it;
childs.erase( it );
return true;
}
return false;
}

//========================================================
// Name : GetAttr
// Desc : get attribute with index in attribute list
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXAttr _tagXMLNode::GetAttr( int i )
{
if( i &gt;= 0 &amp;&amp; i &lt; (int)attrs.size() )
return attrs[i];
return NULL;
}

//========================================================
// Name : GetAttrIterator
// Desc : get attribute iterator
// Param :
// Return : std::vector&lt;LPXAttr&gt;::iterator
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
XAttrs::iterator _tagXMLNode::GetAttrIterator( LPXAttr attr )
{

XAttrs::iterator it = attrs.begin();
for( ; it != attrs.end() ; ++(it) )
{
if( *it == attr )
return it;
}
*it = NULL;
return it;
}

//========================================================
// Name : AppendAttr
// Desc : add attribute
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXAttr _tagXMLNode::AppendAttr( LPXAttr attr )
{
attr-&gt;parent = this;
attrs.push_back( attr );
return attr;
}

//========================================================
// Name : RemoveAttr
// Desc : detach attribute and delete object
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
bool _tagXMLNode::RemoveAttr( LPXAttr attr )
{
XAttrs::iterator it = GetAttrIterator( attr );
if( *it )
{
delete *it;
attrs.erase( it );
return true;
}
return false;
}

//========================================================
// Name : CreateNode
// Desc : Create node object and return it
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXNode _tagXMLNode::CreateNode( LPCTSTR name /*= NULL*/, LPCTSTR value /*= NULL*/ )
{
LPXNode node = new XNode;
node-&gt;name = name;
node-&gt;value = value;
return node;
}

//========================================================
// Name : CreateAttr
// Desc : create Attribute object and return it
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXAttr _tagXMLNode::CreateAttr( LPCTSTR name /*= NULL*/, LPCTSTR value /*= NULL*/ )
{
LPXAttr attr = new XAttr;
attr-&gt;name = name;
attr-&gt;value = value;
return attr;
}

//========================================================
// Name : AppendAttr
// Desc : add attribute
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXAttr _tagXMLNode::AppendAttr( LPCTSTR name /*= NULL*/, LPCTSTR value /*= NULL*/ )
{
return AppendAttr( CreateAttr( name, value ) );
}

//========================================================
// Name : DetachChild
// Desc : no delete object, just detach in list
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXNode _tagXMLNode::DetachChild( LPXNode node )
{
XNodes::iterator it = GetChildIterator( node );
if( *it )
{
childs.erase( it );
return node;
}
return NULL;
}

//========================================================
// Name : DetachAttr
// Desc : no delete object, just detach in list
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXAttr _tagXMLNode::DetachAttr( LPXAttr attr )
{
XAttrs::iterator it = GetAttrIterator( attr );
if( *it )
{
attrs.erase( it );
return attr;
}
return NULL;
}

//========================================================
// Name : CopyNode
// Desc : copy current level node with own attributes
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
void _tagXMLNode::CopyNode( LPXNode node )
{
Close();

doc = node-&gt;doc;
parent = node-&gt;parent;
name = node-&gt;name;
value = node-&gt;value;
type = node-&gt;type;

// copy attributes
for( int i = 0 ; i &lt; (int)node-&gt;attrs.size(); i++)
{
LPXAttr attr = node-&gt;attrs[i];
if( attr )
AppendAttr( attr-&gt;name, attr-&gt;value );
}
}

//========================================================
// Name : _CopyBranch
// Desc : recursive internal copy branch
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
void _tagXMLNode::_CopyBranch( LPXNode node )
{
CopyNode( node );

for( int i = 0 ; i &lt; (int)node-&gt;childs.size(); i++)
{
LPXNode child = node-&gt;childs[i];
if( child )
{
LPXNode mychild = new XNode;
mychild-&gt;CopyNode( child );
AppendChild( mychild );

mychild-&gt;_CopyBranch( child );
}
}
}

//========================================================
// Name : AppendChildBranch
// Desc : add child branch ( deep-copy )
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
LPXNode _tagXMLNode::AppendChildBranch( LPXNode node )
{
LPXNode child = new XNode;
child-&gt;CopyBranch( node );

return AppendChild( child );
}

//========================================================
// Name : CopyBranch
// Desc : copy branch ( deep-copy )
// Param :
// Return :
//--------------------------------------------------------
// Coder Date Desc
// bro 2002-10-29
//========================================================
void _tagXMLNode::CopyBranch( LPXNode branch )
{
Close();

_CopyBranch( branch );
}


_tagXMLEntitys::_tagXMLEntitys( LPXENTITY entities, int count )
{
for( int i = 0; i &lt; count; i++)
push_back( entities[i] );
}

LPXENTITY _tagXMLEntitys::GetEntity( int entity )
{
for( int i = 0 ; i &lt;(int) size(); i ++ )
{
if( at(i).entity == entity )
return LPXENTITY(&amp;at(i));
}
return NULL;
}

LPXENTITY _tagXMLEntitys::GetEntity( LPTSTR entity )
{
for( int i = 0 ; i &lt; (int)size(); i ++ )
{
LPTSTR ref = (LPTSTR)at(i).ref;
LPTSTR ps = entity;
while( ref &amp;&amp; *ref )
if( *ref++ != *ps++ )
break;
if( ref &amp;&amp; !*ref ) // found!
return LPXENTITY(&amp;at(i));
}
return NULL;
}

int _tagXMLEntitys::GetEntityCount( LPCTSTR str )
{
int nCount = 0;
LPTSTR ps = (LPTSTR)str;
while( ps &amp;&amp; *ps )
if( GetEntity( *ps++ ) ) nCount ++;
return nCount;
}

int _tagXMLEntitys::Ref2Entity( LPCTSTR estr, LPTSTR str, int strlen )
{
LPTSTR pes = (LPTSTR)estr;
LPTSTR ps = str;
LPTSTR ps_end = ps+strlen;
while( pes &amp;&amp; *pes &amp;&amp; ps &lt; ps_end )
{
LPXENTITY ent = GetEntity( pes );
if( ent )
{
// copy entity meanning char
*ps = ent-&gt;entity;
pes += ent-&gt;ref_len;
}
else
*ps = *pes++; // default character copy
ps++;
}
*ps = '\0';

// total copied characters
return ps-str;
}

int _tagXMLEntitys::Entity2Ref( LPCTSTR str, LPTSTR estr, int estrlen )
{
LPTSTR ps = (LPTSTR)str;
LPTSTR pes = (LPTSTR)estr;
LPTSTR pes_end = pes+estrlen;
while( ps &amp;&amp; *ps &amp;&amp; pes &lt; pes_end )
{
LPXENTITY ent = GetEntity( *ps );
if( ent )
{
// copy entity string
LPTSTR ref = (LPTSTR)ent-&gt;ref;
while( ref &amp;&amp; *ref )
*pes++ = *ref++;
}
else
*pes++ = *ps; // default character copy
ps++;
}
*pes = '\0';

// total copied characters
return pes-estr;
}

CString _tagXMLEntitys::Ref2Entity( LPCTSTR estr )
{
CString es;
if( estr )
{
int len = _tcslen(estr);
LPTSTR esbuf = es.GetBufferSetLength( len+1 );
if( esbuf )
Ref2Entity( estr, esbuf, len );
}
return es;
}

CString _tagXMLEntitys::Entity2Ref( LPCTSTR str )
{
CString s;
if( str )
{
int nEntityCount = GetEntityCount(str);
if( nEntityCount == 0 )
return CString(str);
int len = _tcslen(str) + nEntityCount*10 ;
LPTSTR sbuf = s.GetBufferSetLength( len+1 );
if( sbuf )
Entity2Ref( str, sbuf, len );
}
return s;
}

CString XRef2Entity( LPCTSTR estr )
{
return entityDefault.Ref2Entity( estr );
}

CString XEntity2Ref( LPCTSTR str )
{
return entityDefault.Entity2Ref( str );
}
GeneralThanks for using XMLite, Device Solutions LLC. Pin
Cho, Kyung-min18-Jan-09 13:39
Cho, Kyung-min18-Jan-09 13:39 
QuestionHow to Create XML doc? Pin
sharath udupi12-Dec-08 1:44
sharath udupi12-Dec-08 1:44 
AnswerRe: How to Create XML doc? Pin
Cho, Kyung-min12-Dec-08 18:08
Cho, Kyung-min12-Dec-08 18:08 
GeneralRe: How to Create XML doc? Pin
sharath udupi15-Dec-08 4:27
sharath udupi15-Dec-08 4:27 
GeneralVC2008 version of XMLite Pin
CycoCPT8-Dec-08 20:25
CycoCPT8-Dec-08 20:25 
GeneralRe: VC2008 version of XMLite Pin
Cho, Kyung-min12-Dec-08 17:58
Cho, Kyung-min12-Dec-08 17:58 
GeneralRe: VC2008 version of XMLite Pin
Humanchao26-Sep-10 16:35
Humanchao26-Sep-10 16:35 
Questionthanks for xmllite !! another question :how to change the attribute value in a xml string ,and how to add a child to a xml string?? Pin
lw840117-Sep-08 16:05
lw840117-Sep-08 16:05 
AnswerRe: thanks for xmllite !! another question :how to change the attribute value in a xml string ,and how to add a child to a xml string?? [modified] Pin
Cho, Kyung-min17-Sep-08 17:26
Cho, Kyung-min17-Sep-08 17:26 
GeneralRe: thanks for xmllite !! another question :how to change the attribute value in a xml string ,and how to add a child to a xml string?? Pin
lw840118-Sep-08 16:45
lw840118-Sep-08 16:45 
General[Message Removed] Pin
nompel20-Sep-08 14:56
nompel20-Sep-08 14:56 
GeneralRe: thanks for xmllite !! another question :how to change the attribute value in a xml string ,and how to add a child to a xml string?? Pin
Cho, Kyung-min20-Sep-08 20:37
Cho, Kyung-min20-Sep-08 20:37 
QuestionCan xmlite Load xml files ??such as temp.xml?? Pin
lw840126-Aug-08 21:21
lw840126-Aug-08 21:21 
AnswerRe: Can xmlite Load xml files ??such as temp.xml?? Pin
Cho, Kyung-min27-Aug-08 13:09
Cho, Kyung-min27-Aug-08 13:09 
GeneralThanks for using xmlite Pin
Cho, Kyung-min30-Jul-08 6:47
Cho, Kyung-min30-Jul-08 6:47 
GeneralReading XML Data from an URL Pin
T.RATHA KRISHNAN15-May-08 1:04
T.RATHA KRISHNAN15-May-08 1:04 
GeneralRe: Reading XML Data from an URL Pin
Cho, Kyung-min19-May-08 13:32
Cho, Kyung-min19-May-08 13:32 

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.