CMarkup的改进

对于使用C++语言,CMarkup由于其灵活、快速的特点,成为很多程序员用来解析XML的一个工具。

但是,由于免费版本不支持XPATH的查找,在Free版本中,当需要在一个XML中定位某个节点时,需要不断的IntoElem,FindElem,很不方便。所以,花了一个下午的时间,特意改写了一个CMarkup类,使其支持以下任意定位和绝对定位的查找:

   markup.FindItem("//Item");                      /* 任意定位 */

   markup.FindItem("/ROOT/ITEMS/ITEM");   /* 绝对定位 */

 

主要改写的点在以下两个函数:

   CMarkup::FindElem()  和 CMarkup::x_FindElem()

 

 改写后的代码如下所示:

 1 bool CMarkup::FindElem( MCD_CSTR szName )
 2 {
 3     if ( m_nDocFlags & MDF_WRITEFILE )
 4         return false;
 5     if ( m_pElemPosTree->GetSize() )
 6     {
 7         // Change current position only if found
 8         PathPos path( szName, false );
 9         if(path.IsAbsolutePath()) {   /* 绝对路径查找时,XML定位到开始位置 */
10             ResetPos();
11         }
12         int iPos = x_FindElem( m_iPosParent, m_iPos, path );
13         if ( iPos )
14         {
15             // Assign new position
16             x_SetPos( ELEM(iPos).iElemParent, iPos, 0 );
17             return true;
18         }
19     }
20     return false;
21 }


 

 1 int CMarkup::x_FindElem( int iPosParent, int iPos, PathPos& path ) const
 2 {
 3     // If pPath is NULL or empty, go to next sibling element
 4     // Otherwise go to next sibling element with matching path
 5     //
 6     if ( ! path.ValidPath() )
 7         return 0;
 8 
 9     // Paths other than simple tag name are only supported in the developer version
10 //    if ( path.IsAnywherePath() || path.IsAbsolutePath() )   /* 原有功能针对绝对定位及任意定位查找时,直接返回. */
11 //        return 0;
12 
13     if ( iPos )
14         iPos = ELEM(iPos).iElemNext;
15     else
16         iPos = ELEM(iPosParent).iElemChild;
17 
18     // Finished here if pPath not specified
19     if ( ! path.IsPath() )
20         return iPos;
21 
22     // Search
23     MCD_PCSZ strTmp;
24     int iParent = iPos;
25     int iOldPos = 0;
26     TokenPos token( m_strDoc, m_nDocFlags );
27     if(path.IsAbsolutePath() || path.IsAnywherePath())   /*  取得查找的路径, 删除查找字符串前面的 '/' 符号 */
28         strTmp = path.GetWordAndInc();
29     while ( iPos )
30     {
31         // Compare tag name
32         token.m_nNext = ELEM(iPos).nStart + 1;
33         token.FindName(); // Locate tag name
34         if ( token.Match(strTmp) )
35         {
36             if (path.IsAtPathEnd())   /*  针对绝对路径查找,查找到最后一个Token时返回 */
37             {    
38                 return iPos;   /*  匹配成功 */
39             }
40             else
41             {
42                 path.IncChar();
43                 strTmp = path.GetWordAndInc();   /*  针对绝对路径查找,剥离一个路径。如 [ROOT/ITEMS/ITEM] →[ITEMS/ITEM]  */
44                 iPos = ELEM(iPos).iElemChild;
45                 continue;
46             }
47         }
48         else {
49              path.IncChar();
50              iOldPos = iPos;
51              iPos = ELEM(iPos).iElemChild;  /* 当前节点无法匹配,进入子节点进行匹配 */
52              if(iPos)
53                   continue;
54              else
55                   iPos = iOldPos;
56              if( path.IsAtPathEnd() ) 
57                   iPos = ELEM(ELEM(iPos).iElemParent).iElemNext;  /* 子节点无法匹配,向邻居节点进行匹配 */
58              continue;
59         }
60         iPos = ELEM(iPos).iElemNext;
61     }
62     return 0;
63 
64 }


以上、一时还有一些没考虑到的情况,不过经过一些简单测试,至少是可以使用的。

posted @ 2010-11-29 17:01  shipfi  阅读(...)  评论(...编辑  收藏