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 }
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 }
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 }
以上、一时还有一些没考虑到的情况,不过经过一些简单测试,至少是可以使用的。