65.9K
CodeProject 正在变化。 阅读更多。
Home

XMLite: 简单的 XML 解析器。

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.65/5 (45投票s)

2002 年 12 月 26 日

CPOL

3分钟阅读

viewsIcon

773945

downloadIcon

15647

易于访问且简单的 XML 解析器

Sample Image - XMLite1.gif

为什么选择 XMLite?

在我之前的项目中,我需要一个简单的 XML 解析器。我使用 Jabber 服务器。由于时间有限,我使用了名为 Jabbercom 的 Jabber 客户端库,它是一个基于 Win32 COM 的 DLL 模块。 Jabber 协议基于 XML。但是,该库对于我的项目来说并不是一个完整的 XML 解析器。

首先,它无法支持韩语文本(可能还有其他语言),并且没有转义字符处理,也没有实体编码/解码支持。我必须替换 XML 解析引擎,但我不能使用 MSXML 和 Expat,并且它们要么安装麻烦,要么难以使用。所以我决定制作 XMLite。它不是一个完全支持的 XML 解析器,但它简单且体积小,所以我希望它能帮助到某人。

使用 XMLite

简单来说,XMLite 有两个主要的数据结构,XNodeXAttrXNode 用于 XML 元素节点,XAttr 用于 XML 属性节点。XNode 具有子 XNodes 和自己的属性列表 XAttrs。如果你查看我的源代码,你会认为代码很容易理解和使用。代码很简单。

  1. 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

    结果显示在上面的图片中。

  2. 遍历已解析的 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 修改

    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>
  4. 错误处理

    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.
  5. 实体和转义字符测试

    XMLite 有转义处理。但这个更新版本没有针对一般情况的转义。但你仍然可以在解析值时使用转义字符。

    pi.escape_value = '\\' 

    大写字母,转义字符是

    '\'
    类似于 C/C++。并且它有实体处理。实体表如下所示
    特殊字符 特殊含义 实体编码
    > 开始一个标签。 >
    < 结束一个标签。 <
    " 引号。 "
    ' 撇号。 &apos;
    & 和号。 &
    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='<&apos;asdf">' >asdf</TAG>
    </XML>
  6. 配置解析和显示

    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>
  7. 自定义实体表

    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 )  );
  8. 分支复制(深拷贝)

    现在 XMLite 可以复制分支。

    void CTestXMLiteDlg::OnButton9() 
    {
        // TODO: Add your control notification handler code here
        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()  );
    
            // 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. 使用 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()  );
    }
  10. 解析格式错误的 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() );
     } 
    }
  11. 深度查找

    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,请将其交给我,以便所有人都能使用。谢谢。

参考

© . All rights reserved.