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.
-
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"));
The result is shown in the picture above.
-
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;
LPXNode child;
for( i = 0 ; i < xml.GetChildCount(); i++)
{
child = xml.GetChild(i);
AfxMessageBox( child->GetXML() );
}
childs = xml.GetChilds();
for( i = 0 ; i < childs.size(); i++)
AfxMessageBox( childs[i]->GetXML() );
childs = xml.GetChilds(_T("Person") );
for( i = 0 ; i < childs.size(); i++)
{
AfxMessageBox( childs[i]->GetXML() );
}
AfxMessageBox( xml.GetChildAttrValue( _T("Information"), _T("count") ) );
int count = XStr2Int( xml.GetChildAttrValue( _T("Information"),
_T("count") ));
ASSERT( count == 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 );
LPXNode child_bro = xml.GetChild(0);
xml.RemoveChild( child_bro );
AfxMessageBox(xml.GetXML());
Result: there is no bro node.
<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>
-
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 )
{
AfxMessageBox( pi.error_string );
AfxMessageBox( xml.GetXML() );
}
else
ASSERT(FALSE);
then, result is
'<NoCloseTag> ... </XML>' is not wel-formed.
-
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 character |
Special meaning |
Entity encoding |
> |
Begins a tag. |
> |
< |
Ends a tag. |
< |
" |
Quotation mark. |
" |
' |
Apostrophe. |
' |
& |
Ampersand. |
& |
CString sxml;
sxml = _T("<XML>\
<TAG attr='<\\'asdf\\\">'>asdf</TAG>\
</XML>");
XNode xml;
PARSEINFO pi;
pi.escape_value = '\\'
xml.Load( sxml, &pi );
AfxMessageBox( xml.GetXML() );
Result:
<XML>
<TAG attr='<'asdf">' >asdf</TAG>
</XML>
-
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;
xml.Load( sxml, &pi );
AfxMessageBox( xml.GetXML() );
DISP_OPT opt;
opt.newline = false;
AfxMessageBox( xml.GetXML( &opt ) );
Result:
first,
<XML>
<TAG attr=' qwer ' > asdf </TAG>
</XML>
after,
<XML><TAG attr='qwer' >asdf</TAG></XML>
-
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>");
static const XENTITY entity_table[] = {
{ '<', _T("<"), 4 } ,
{ '&', _T("&"), 5 }
};
XENTITYS entitys( (LPXENTITY)entity_table, 2 ) ;
PARSEINFO pi;
XNode xml;
pi.entity_value = true;
pi.entitys = &entitys;
xml.Load( sxml, &pi );
AfxMessageBox( xml.GetXML() );
DISP_OPT opt;
opt.entitys = &entitys;
opt.reference_value = true;
AfxMessageBox( xml.GetXML( &opt ) );
-
branch copy (deep-copy)
Now XMLite can copy branch.
void CTestXMLiteDlg::OnButton9()
{
CString sxml;
sxml = _T(""\"</span>book"" />\
"me"" /><NAME>Cho,Kyung Min</NAME><NICK>bro</NICK>\
"friend"" /><NAME>Baik,Ji Hoon</NAME><NICK>bjh</NICK>\
"friend"" /><NAME>Bak,Gun Joo</NAME><NICK>dichter</NICK>\
"3"" />\
");
XNode xml;
xml.Load( sxml );
AfxMessageBox( xml.GetXML() );
XNode xml2;
xml2.CopyNode( &xml );
AfxMessageBox( xml2.GetXML() );
XNode xml3;
xml3.CopyBranch( &xml );
AfxMessageBox( xml3.GetXML() );
XNode xml4;
xml4.AppendChildBranch( &xml );
AfxMessageBox( xml4.GetXML() );
}
-
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()
{
CString sxml;
sxml = _T("<?xml version='1.0'?>\
\
<![CDATA[some data]]>\
\
<![CDATA[some data]]>\
value\
<![CDATA[some data2]]>\
<!-- comment2-->");
XNode xml;
xml.Load( sxml );
AfxMessageBox( xml.GetXML() );
}
-
Parsing un-welformed xml (like HTML)
Now XMLite can parse un-welformed xml like HTML with 'force_parse' attribute
void CTestXMLiteDlg::OnButton11()
{
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();
AfxMessageBox( xml.GetXML() );
}
XNode node;
if( node.Load( sXML ) )
{
AfxMessageBox( node.GetXML() );
}
}
-
Deep-Find
XMLite's node can search own all children with tag name.
CString sXML = "\
\
\
<C/>\
<D/>\
\
";
XNode node;
if( node.Load( sXML ) )
{
AfxMessageBox( node.GetXML() );
LPXNode found = NULL;
found = node.Find( _T("D") );
if( found )
{
AfxMessageBox( found->GetXML() );
}
}
History
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