XMLite: 简单的 XML 解析器。






4.65/5 (45投票s)
易于访问且简单的 XML 解析器
为什么选择 XMLite?
在我之前的项目中,我需要一个简单的 XML 解析器。我使用 Jabber 服务器。由于时间有限,我使用了名为 Jabbercom 的 Jabber 客户端库,它是一个基于 Win32 COM 的 DLL 模块。 Jabber 协议基于 XML。但是,该库对于我的项目来说并不是一个完整的 XML 解析器。
首先,它无法支持韩语文本(可能还有其他语言),并且没有转义字符处理,也没有实体编码/解码支持。我必须替换 XML 解析引擎,但我不能使用 MSXML 和 Expat,并且它们要么安装麻烦,要么难以使用。所以我决定制作 XMLite。它不是一个完全支持的 XML 解析器,但它简单且体积小,所以我希望它能帮助到某人。
使用 XMLite
简单来说,XMLite 有两个主要的数据结构,XNode
和 XAttr
。XNode
用于 XML 元素节点,XAttr
用于 XML 属性节点。XNode
具有子 XNodes
和自己的属性列表 XAttrs
。如果你查看我的源代码,你会认为代码很容易理解和使用。代码很简单。
-
XML 解析
XMLite 可以解析像下面这样的 XML 标签节点纯文本。你可以检查解析错误。如果
XNode::Load
返回NULL
,那么你可以知道纯 XML 文本存在一些错误。如果你想了解更多错误信息,请转到第 4 节 - 错误处理。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
结果显示在上面的图片中。
-
遍历已解析的 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 );
-
DOM 修改
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());
结果:没有 bro 节点。
<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>
-
错误处理
XMLite 有 XML 错误处理,但它不完整。
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);
然后,结果是
'<NoCloseTag> ... </XML>' is not wel-formed.
-
实体和转义字符测试
XMLite 有转义处理。但这个更新版本没有针对一般情况的转义。但你仍然可以在解析值时使用转义字符。
pi.escape_value = '\\'
大写字母,转义字符是
'\'
类似于 C/C++。并且它有实体处理。实体表如下所示特殊字符 特殊含义 实体编码 > 开始一个标签。 > < 结束一个标签。 < " 引号。 " ' 撇号。 ' & 和号。 & 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() );
结果
<XML> <TAG attr='<'asdf">' >asdf</TAG> </XML>
-
配置解析和显示
XMLite 可以在解析时进行修剪,并在显示时添加换行符(默认)。
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 ) );
结果
首先,
<XML> <TAG attr=' qwer ' > asdf </TAG> </XML>
之后,
<XML><TAG attr='qwer' >asdf</TAG></XML>
-
自定义实体表
XMLite 可以自定义实体表以进行特殊解析和显示。你可以定义新的实体表以进行自定义解析。
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 ) );
-
分支复制(深拷贝)
现在 XMLite 可以复制分支。
void CTestXMLiteDlg::OnButton9() { // TODO: Add your control notification handler code here CString sxml; sxml = _T("
"\"</span>book"" />\ "); 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() ); }"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"" />\ -
使用 PI/CDATA/注释解析 xml
现在 XMLite 可以使用 PI/CDATA/注释进行解析。但 XMLite 仍然不支持 PI 的编码功能。
void CTestXMLiteDlg::OnButton10() { // TODO: Add your control notification handler code here 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() ); }
-
解析格式错误的 xml(如 HTML)
现在,XMLite 可以使用 'force_parse' 属性解析格式错误的 xml,如 HTML
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() ); } }
-
深度查找
XMLite 的节点可以使用标签名称搜索自己的所有子节点。
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() ); } }
历史
// 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
许可证
有时我收到关于 XMLite 许可证的电子邮件。你可以出于商业/非商业目的使用/修改/重新分发 XMLite。但是,请给我发送一封感谢电子邮件,其中包含你的项目信息。
然后我会很高兴并将其添加到 XMLite 的参考文献中。如果你修复或更新了 XMLite,请将其交给我,以便所有人都能使用。谢谢。