CMarkup的改进

 CMarkup是处理XML的一个不错的选择。但是我们下到的免费版本是不支持XPath的,这意味着我们为了查找一个内容,需要多次调用FindElem或再FindChildElem。而不能这样 xml.FindElem("/ROOT/B/C/D")。

而它的Developer版本是支持Path的,但它的Path与XPath仍然不同。详情请参考http://www.firstobject.com/dn_markpath.htm(Paths In CMarkup)英文不好,没仔细看。

但是在免费版本中为了实现Path难道非得一次又一次地调用FindElem或者FindChildElem吗?

 

通过不太仔细地研读它的源码,我有了以下发现。

 

FindElem调用了x_FindElem,它的声明如下:

 int x_FindElem( int iPosParent, int iPos, PathPos& path ) const;

其中的入参PathPos& path就是记录要查找的路径的,

如果找到了path指定的内容就返回一个数,也就是位置,否则返回0.

在x_FindElem里,有以下代码:


 // Paths other than simple tag name are only supported in the developer version
  if ( path.IsAnywherePath() || path.IsAbsolutePath() )
   return 0;

这意味着我们查找一个路径的时候它根本就不查找了,直接返回了0.

那么我们是不是可以做些工作使它能够返回我们想要的位置呢?

 

接着看下去,

 TokenPos token( m_strDoc, m_nDocFlags );
 while ( iPos )
 {
  // Compare tag name
  token.m_nNext = ELEM(iPos).nStart + 1;
  token.FindName(); // Locate tag name
  if ( token.Match(path.GetPtr()) )
   return iPos;
  iPos = ELEM(iPos).iElemNext;
 }
 return 0;

 

看来这里就是查找的过程了。

看来TokenPos 也是一个比较重要的东西。通过一番调试发现,原来TokenPos 是用来记录当前查找的位置的。在查找时它和要查找的path进行匹配,如果能匹配就返回该位置。

如果path是"/ROOT/B/C/D", token.Match(path.GetPtr()) 为真,它就返回了,在此时我们显然是不希望它返回,而是希望它去查找它的子结点,一直匹配到path的末尾的时候才返回。

所以需要把它改成如下代码

 

 

 TokenPos token( m_strDoc, m_nDocFlags );

 while ( iPos )
 {
  // Compare tag name
  token.m_nNext = ELEM(iPos).nStart + 1;
  token.FindName(); // Locate tag name
  if ( token.Match(path.GetPtr()) )
  {
   path.GetWordAndInc();
   if (path.IsAtPathEnd())
   {    
    return iPos;
   }else
   {
    path.IncChar();
    iPos = ELEM(iPos).iElemChild;
    continue;
   }
  }
  iPos = ELEM(iPos).iElemNext;
 }

 

通过以上改动再执行xml.FindElem("/ROOT/B/C/D")就可以返回真了。当然如果想多次调用它还得在FindElem里面改动一下:

 

bool CMarkup::FindElem( MCD_CSTR szName )
{
 if ( m_nDocFlags & MDF_WRITEFILE )
  return false;
 if ( m_pElemPosTree->GetSize() )
 {
  // Change current position only if found
  PathPos path( szName, false );
  //
  if(path.IsAbsolutePath())
  {
   ResetPos();
  }
  //

  int iPos = x_FindElem( m_iPosParent, m_iPos, path );
  if ( iPos )
  {
   // Assign new position
   x_SetPos( ELEM(iPos).iElemParent, iPos, 0 );
   return true;
  }
 }
 return false;
}

改后的x_FindElem如下

int CMarkup::x_FindElem( int iPosParent, int iPos, PathPos& path ) const
{
 // If pPath is NULL or empty, go to next sibling element
 // Otherwise go to next sibling element with matching path
 //
 if ( ! path.ValidPath() )
  return 0;

 // Paths other than simple tag name are only supported in the developer version
//  if ( path.IsAnywherePath() || path.IsAbsolutePath() )
//   return 0;


 if ( iPos )
  iPos = ELEM(iPos).iElemNext;
 else
  iPos = ELEM(iPosParent).iElemChild;

 // Finished here if pPath not specified
 if ( ! path.IsPath() )
  return iPos;

 // Search

 TokenPos token( m_strDoc, m_nDocFlags );

 while ( iPos )
 {
  // Compare tag name
  token.m_nNext = ELEM(iPos).nStart + 1;
  token.FindName(); // Locate tag name
  if ( token.Match(path.GetPtr()) )
  {
   path.GetWordAndInc();
   if (path.IsAtPathEnd())
   {    
    return iPos;
   }else
   {
    path.IncChar();
    iPos = ELEM(iPos).iElemChild;
    continue;
   }

  }
  iPos = ELEM(iPos).iElemNext;
 }
 return 0;

}

当然以上的改动似乎并没有达到Developer版本的水平,还希望高手支招啊!

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页