以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 XML工具及XML开发环境 』  (http://bbs.xml.org.cn/list.asp?boardid=7)
----  哪位有C或C++编写xml解析器的源代码  (http://bbs.xml.org.cn/dispbbs.asp?boardid=7&rootid=&id=18691)


--  作者:Starplain
--  发布时间:5/23/2005 7:33:00 AM

--  哪位有C或C++编写xml解析器的源代码
急呀!!哪位高手有c或c++编写xml解析器的源代码!!!!!!!!!!!请指教!!!
--  作者:haomeng1999
--  发布时间:5/24/2005 3:30:00 PM

--  
我好像贴过一个

--  作者:liuliu1030
--  发布时间:5/26/2005 3:40:00 PM

--  
wo wo也需要啊,liuliu1030@hotmail.com
--  作者:luanyun0901
--  发布时间:5/28/2005 9:15:00 AM

--  
二楼的,能发一个给我吗,cherry_gm_david@yahoo.com.cn

--  作者:kathy_lj
--  发布时间:6/6/2005 9:38:00 PM

--  
我也想要一个,谢谢,kathy_lj@163.com
--  作者:RedShadow
--  发布时间:6/6/2005 11:18:00 PM

--  
二楼的,给我一个啊。邮箱:KNIFE13579@126.com,3KY!
--  作者:Dannyzhu
--  发布时间:6/18/2005 5:30:00 PM

--  
二楼的兄弟,能发一个给我吗? zhuchunpeng@yahoo.com.cn

--  作者:Dannyzhu
--  发布时间:6/18/2005 5:47:00 PM

--  

二楼的,能发一个给我吗? E-mail:  zhuchunpeng@yahoo.com.cn

--  作者:phq158
--  发布时间:7/13/2005 9:14:00 AM

--  
二楼的,能发一个给我吗? E-mail:  panghaiquan2005@sina.com


--  作者:WtoG
--  发布时间:7/16/2005 11:04:00 AM

--  
二楼的,能发一个给我吗? E-mail:  w2p2@sohu.com

--  作者:zjb
--  发布时间:7/17/2005 6:51:00 PM

--  
我也需要。jiabin.net@163.com。跟我联系
--  作者:hero_gg
--  发布时间:7/19/2005 4:10:00 PM

--  
我有,QQ联系:262996806
--  作者:zxjbug
--  发布时间:7/19/2005 7:35:00 PM

--  
libxml也是一个好的工具啊,可是我没有相关的资料
--  作者:KnightIACN
--  发布时间:8/26/2005 3:41:00 PM

--  
二楼的,我也想要啊。
Knightworld@tom.com
--  作者:KnightIACN
--  发布时间:8/26/2005 3:43:00 PM

--  
我也想要啊,先谢谢了!
Knightworld@tom.com
--  作者:zjianhu
--  发布时间:8/26/2005 3:58:00 PM

--  
同问
--  作者:romeo.zhang
--  发布时间:9/4/2005 6:11:00 PM

--  
我也要!romeo.zhang@163.com
--  作者:bbface_bbs
--  发布时间:9/22/2005 12:07:00 PM

--  
以下是引用haomeng1999在2005-5-24 15:30:00的发言:
我好像贴过一个


我也要bbface@citiz.net,请发给我,谢谢了。


--  作者:husthit
--  发布时间:9/22/2005 9:24:00 PM

--  
给我也发一个把!liyucheng1111@163.com
--  作者:yzff
--  发布时间:10/24/2005 9:21:00 AM

--  
我也要一个,多谢了!!yuzf@zj.com
--  作者:ahngzw
--  发布时间:10/24/2005 3:42:00 PM

--  
我也想要一个   ahngzw@163.com
--  作者:polypf
--  发布时间:11/6/2005 8:11:00 PM

--  
二楼的,能发一个给我吗? E-mail:   polypf@sohu.com  谢谢了,我也要一个
--  作者:zhhxidian
--  发布时间:11/20/2005 10:49:00 PM

--  
二楼的兄弟,我现在急需C++编写的xml解析器,能否给我一个,zhhxidian2005@126.com万分感谢!
--  作者:liqiyu
--  发布时间:11/23/2005 4:16:00 PM

--  
tinyxml 是有源码的
--  作者:megan
--  发布时间:3/13/2006 10:38:00 AM

--  
二楼的兄弟可以发一个给我吗?
meganlz@163.com
谢谢
--  作者:CFeng
--  发布时间:3/29/2006 12:07:00 PM

--  
不错不错
--  作者:szlidong
--  发布时间:3/30/2006 7:47:00 AM

--  
我也要:sz_lidong@hotmail.com
--  作者:dk2
--  发布时间:3/31/2006 3:30:00 PM

--  
二楼的高手 给我一个吧
dungeonkeeper2@sina.com
--  作者:phenix4288
--  发布时间:4/2/2006 2:47:00 PM

--  
最近做毕业设计,也要用到,给我一个吧,谢谢
phenix4288@163.com
--  作者:lmjanson
--  发布时间:4/5/2006 5:29:00 PM

--  
2楼的大哥,也给小弟一个,谢谢!
lmjanson@163.com
--  作者:ImmenseLH
--  发布时间:4/8/2006 6:29:00 PM

--  
我也要!!!
毕业设计用到一些东东 linhai5160@hotmail.com
--  作者:lihanhui_2002
--  发布时间:4/8/2006 8:31:00 PM

--  
偶也急需啊,二楼的兄弟,lihanhui_2002@163.com
--  作者:zz277
--  发布时间:4/10/2006 4:20:00 PM

--  
毕设要用到
二楼的兄弟帮忙传一个吧
sfengbupt@sina.com

谢谢


--  作者:fzzmeng
--  发布时间:4/13/2006 4:55:00 PM

--  
2楼的大哥给我也发个吧~~
先谢谢了~
zryczy@126.com
--  作者:chenhm66
--  发布时间:4/14/2006 10:15:00 AM

--  可以给我发一份吗?谢谢
我也需要,发一份好吗?多谢啦!chenhm66@126.com
--  作者:larkcom
--  发布时间:4/20/2006 9:16:00 PM

--  
www.apache.org上有xerces
另外,还有java写的kxml可用
--  作者:xuexic
--  发布时间:4/22/2006 7:55:00 AM

--  
我也要一个最好和c和xml和结合的例子,多谢了!!!
xiaofeng_home@163.com
--  作者:xuexic
--  发布时间:4/22/2006 7:57:00 AM

--  
二楼的能发一个给我吗多谢了
xiaofeng_home@163.com
--  作者:huwei_059_0
--  发布时间:4/22/2006 4:54:00 PM

--  
偶需要一个C语言编写的XML解析器。急用。huwei_059_0@163.com
谢谢了。

--  作者:xiaoxiaoyayi
--  发布时间:4/27/2006 12:00:00 PM

--  
二楼的,俺也需要一个,liwolf82@126.com
谢谢
--  作者:zhu_ruixian
--  发布时间:4/27/2006 12:40:00 PM

--  
// Markup.h: interface for the CMarkup class.


#if !defined(AFX_MARKUP_H__948A2705_9E68_11D2_A0BF_00105A27C570__INCLUDED_)
#define AFX_MARKUP_H__948A2705_9E68_11D2_A0BF_00105A27C570__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <afxtempl.h>

class CMarkup  
{
public:
 CMarkup() { SetDoc( NULL ); };
 CMarkup( LPCTSTR szDoc ) { SetDoc( szDoc ); };
 CMarkup( const CMarkup& markup ) { *this = markup; };
 void operator=( const CMarkup& markup );
 virtual ~CMarkup() {};

 // Navigate
 bool SetDoc( LPCTSTR szDoc );
 bool IsWellFormed();
 bool FindElem( LPCTSTR szName=NULL );
 bool FindChildElem( LPCTSTR szName=NULL );
 bool IntoElem();
 bool OutOfElem();
 void ResetChildPos() { m_iPosChild = 0; };
 void ResetPos();
 CString GetTagName() const { return x_GetTagName(m_iPos); };
 CString GetChildTagName() const { return x_GetTagName(m_iPosChild); };
 CString GetData() const { return x_GetData(m_iPos); };
 CString GetChildData() const { return x_GetData(m_iPosChild); };
 CString GetAttrib( LPCTSTR szAttrib ) const { return x_GetAttrib(m_iPos,szAttrib); };
 CString GetChildAttrib( LPCTSTR szAttrib ) const { return x_GetAttrib(m_iPosChild,szAttrib); };
 bool GetOffsets( int& nStart, int& nEnd ) const;
 CString GetError() const { return m_csError; };

 // Create
 CString GetDoc() const { return m_csDoc; };
 bool AddElem( LPCTSTR szName, LPCTSTR szData=NULL );
 bool AddChildElem( LPCTSTR szName, LPCTSTR szData=NULL );
 bool AddAttrib( LPCTSTR szAttrib, LPCTSTR szValue );
 bool AddChildAttrib( LPCTSTR szAttrib, LPCTSTR szValue );

protected:
 CString m_csDoc;
 int m_nLevel;
 CString m_csError;

 struct ElemPos
 {
  ElemPos() { Clear(); };
  ElemPos( const ElemPos& pos ) { *this = pos; };
  bool IsEmptyElement() const { return (nStartR == nEndL + 1); };
  void Clear()
  {
   nStartL=0; nStartR=0; nEndL=0; nEndR=0; nNext=0;
   iElemParent=0; iElemChild=0; iElemNext=0;
  };
  int nStartL;
  int nStartR;
  int nEndL;
  int nEndR;
  int nNext;
  int iElemParent;
  int iElemChild;
  int iElemNext;
 };

 CArray< ElemPos, ElemPos& > m_aPos;
 int m_iPos;
 int m_iPosChild;
 int m_iPosFree;

 int x_GetFreePos();
 int x_ReleasePos();

 struct TokenPos
 {
  TokenPos() { Clear(); };
  bool IsValid() const { return (nL <= nR); };
  void Clear() { nL=0; nR=-1; bIsString=false; };
  int nL;
  int nR;
  int nNext;
  bool bIsString;
 };

 int x_ParseElem( int iPos );
 int x_ParseError( LPCTSTR szError, LPCTSTR szTag = NULL );
 bool x_FindChar( int&n, _TCHAR c ) const;
 bool x_FindToken( TokenPos& token ) const;
 CString x_GetToken( const TokenPos& token ) const;
 CString x_GetTagName( int iPos ) const;
 CString x_GetData( int iPos ) const;
 CString x_GetAttrib( int iPos, LPCTSTR szAttrib ) const;
 int x_Add( int iPosParent, int iPosBefore, LPCTSTR szName, LPCTSTR szValue );
 bool x_FindAttrib( TokenPos& token, LPCTSTR szAttrib=NULL ) const;
 int x_AddAttrib( int iPos, LPCTSTR szAttrib, LPCTSTR szValue );
 int x_SetAttrib( int iPos, LPCTSTR szAttrib, LPCTSTR szValue );
 bool x_SetData( int iPos, LPCTSTR szData, int nCDATA );
 void x_DocChange( int nLeft, int nReplace, const CString& csInsert );
 void x_PosInsert( int iPos, int nInsertLength );
 void x_Adjust( int iPos, int nShift );
 CString x_TextToDoc( LPCTSTR szText, bool bAttrib = false ) const;
 CString x_TextFromDoc( int nLeft, int nRight ) const;
};

#endif // !defined(AFX_MARKUP_H__948A2705_9E68_11D2_A0BF_00105A27C570__INCLUDED_)
//Marup.cpp

#include "stdafx.h"
#include "afxconv.h"
#include "Markup.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

void CMarkup::operator=( const CMarkup& markup )
{
 m_iPos = markup.m_iPos;
 m_iPosChild = markup.m_iPosChild;
 m_iPosFree = markup.m_iPosFree;
 m_aPos.RemoveAll();
 m_aPos.Append( markup.m_aPos );
 m_nLevel = markup.m_nLevel;
 m_csDoc = markup.m_csDoc;
}

void CMarkup::ResetPos()
{
 // Reset the main and child positions
 m_iPos = 0;
 m_iPosChild = 0;
 m_nLevel = 0;
};

bool CMarkup::SetDoc( LPCTSTR szDoc )
{
 // Reset indexes
 m_iPosFree = 1;
 ResetPos();

 // Set document text
 if ( szDoc )
  m_csDoc = szDoc;
 else
  m_csDoc.Empty();

 // Starting size of position array: 1 element per 64 bytes of document
 // Tight fit when parsing small doc, only 0 to 2 reallocs when parsing large doc
 // Start at 8 when creating new document
 int nStartSize = m_csDoc.GetLength() / 64 + 8;
 if ( m_aPos.GetSize() < nStartSize )
  m_aPos.SetSize( nStartSize );

 // Parse document
 bool bWellFormed = false;
 if ( m_csDoc.GetLength() )
 {
  m_aPos[0].Clear();
  int iPos = x_ParseElem( 0 );
  if ( iPos > 0 )
  {
   m_aPos[0].iElemChild = iPos;
   bWellFormed = true;
  }
 }

 // Clear indexes if parse failed or empty document
 if ( ! bWellFormed )
 {
  m_aPos[0].Clear();
  m_iPosFree = 1;
 }

 ResetPos();
 return bWellFormed;
};

bool CMarkup::IsWellFormed()
{
 if ( m_aPos.GetSize() && m_aPos[0].iElemChild )
  return TRUE;
 return FALSE;
}

bool CMarkup::FindElem( LPCTSTR szName )
{
 // If szName is NULL or empty, go to next sibling element
 // Otherwise go to next sibling element with matching tag name
 // If the current position is valid, start looking from next
 // Change current position only if found
 //
 int iPos = m_iPos;
 if ( ! iPos )
 {
  if ( m_aPos.GetSize() )
   iPos = m_aPos[0].iElemChild;
 }
 else
 {
  iPos = m_aPos[iPos].iElemNext;
 }

 while ( iPos )
 {
  // Compare tag name unless szName is not specified
  if ( szName == NULL || !szName[0] || x_GetTagName(iPos) == szName )
  {
   // Assign new position
   m_iPos = iPos;
   m_iPosChild = 0;
   return true;
  }
  iPos = m_aPos[iPos].iElemNext;
 }
 return false;
}

bool CMarkup::FindChildElem( LPCTSTR szName )
{
 // If szName is NULL or empty, go to next sibling child element
 // Otherwise go to next sibling child element with matching tag name
 // If the current child position is valid, start looking from next
 // Change current child position only if found
 //
 // Shorthand: call this with no current position means under root element
 if ( ! m_iPos )
  FindElem();

 // Is main position valid and not empty?
 if ( ! m_iPos || m_aPos[m_iPos].IsEmptyElement() )
  return false;

 // Is current child position valid?
 int iPosChild = m_iPosChild;
 if ( iPosChild )
  iPosChild = m_aPos[iPosChild].iElemNext;
 else
  iPosChild = m_aPos[m_iPos].iElemChild;

 // Search
 while ( iPosChild )
 {
  // Compare tag name unless szName is not specified
  if ( szName == NULL || !szName[0] || x_GetTagName(iPosChild) == szName )
  {
   // Assign new position
   m_iPosChild = iPosChild;
   return true;
  }
  iPosChild = m_aPos[iPosChild].iElemNext;
 }
 return false;
}

bool CMarkup::IntoElem()
{
 // Find child element unless there is already a child element position
 if ( ! m_iPosChild )
  FindChildElem();

 if ( m_iPosChild )
 {
  m_iPos = m_iPosChild;
  m_iPosChild = 0;
  ++m_nLevel;
  return true;
 }

 return false;
}

bool CMarkup::OutOfElem()
{
 // Go to parent element
 if ( m_iPos && m_nLevel > 0 )
 {
  m_iPosChild = m_iPos;
  m_iPos = m_aPos[m_iPos].iElemParent;
  --m_nLevel;
  return true;
 }
 return false;
}

bool CMarkup::GetOffsets( int& nStart, int& nEnd ) const
{
 // Return document offsets of current main position element
 // This is not part of EDOM but is used by the Markup project
 if ( m_iPos )
 {
  nStart = m_aPos[m_iPos].nStartL;
  nEnd = m_aPos[m_iPos].nEndR;
  return true;
 }
 return false;
}

bool CMarkup::AddElem( LPCTSTR szName, LPCTSTR szValue )
{
 // Add an element after current main position
 int iPosParent = m_iPos? m_aPos[m_iPos].iElemParent : 0;
 m_iPosChild = 0;

 // Setting root element?
 if ( iPosParent == 0 )
 {
  if ( IsWellFormed() )
   return false;

  m_csDoc.Empty();
 }

 m_iPos = x_Add( iPosParent, m_iPos, szName, szValue );
 return true;
}

bool CMarkup::AddChildElem( LPCTSTR szName, LPCTSTR szValue )
{
 // Add a child element under main position, after current child position
 if ( ! m_iPos )
  return false;

 // If no child position, add after last sibling
 int iPosLast = m_aPos[m_iPos].iElemChild;
 if ( ! m_iPosChild && iPosLast )
 {
  m_iPosChild = iPosLast;
  while ( (iPosLast=m_aPos[iPosLast].iElemNext) != 0 )
   m_iPosChild = iPosLast;
 }

 m_iPosChild = x_Add( m_iPos, m_iPosChild, szName, szValue );
 return true;
}

bool CMarkup::AddAttrib( LPCTSTR szAttrib, LPCTSTR szValue )
{
 // Add attribute to current main position element
 if ( m_iPos )
 {
  x_AddAttrib( m_iPos, szAttrib, szValue );
  return true;
 }
 return false;
}

bool CMarkup::AddChildAttrib( LPCTSTR szAttrib, LPCTSTR szValue )
{
 // Add attribute to current child position element
 if ( m_iPosChild )
 {
  x_AddAttrib( m_iPosChild, szAttrib, szValue );
  return true;
 }
 return false;
}

//////////////////////////////////////////////////////////////////////
// Private Methods
//////////////////////////////////////////////////////////////////////

int CMarkup::x_GetFreePos()
{
 //
 // This returns the index of the next unused ElemPos in the array
 //
 if ( m_iPosFree == m_aPos.GetSize() )
  m_aPos.SetSize( m_iPosFree + m_iPosFree / 2 );
 ++m_iPosFree;
 return m_iPosFree - 1;
}

int CMarkup::x_ReleasePos()
{
 //
 // This decrements the index of the next unused ElemPos in the array
 // allowing the element index returned by GetFreePos() to be reused
 //
 --m_iPosFree;
 return 0;
}

int CMarkup::x_ParseError( LPCTSTR szError, LPCTSTR szTag )
{
 if ( szTag )
  m_csError.Format( szError, szTag );
 else
  m_csError = szError;
 x_ReleasePos();
 return -1;
}

int CMarkup::x_ParseElem( int iPosParent )
{
 // This is either called by SetDoc, x_AddSubDoc, or itself recursively
 // m_aPos[iPosParent].nEndL is where to start parsing for the child element
 // This returns the new position if a tag is found, otherwise zero
 // In all cases we need to get a new ElemPos, but release it if unused
 //
 int iPos = x_GetFreePos();
 m_aPos[iPos].nStartL = m_aPos[iPosParent].nEndL;
 m_aPos[iPos].nNext = m_aPos[iPosParent].nStartR + 1;
 m_aPos[iPos].iElemParent = iPosParent;
 m_aPos[iPos].iElemChild = 0;
 m_aPos[iPos].iElemNext = 0;

 // Start Tag
 // A loop is used to ignore all remarks tags and special tags
 // i.e. <?xml version="1.0"?>, and <!-- comment here -->
 // So any tag beginning with ? or ! is ignored
 // Loop past ignored tags
 TokenPos token;
 token.nNext = m_aPos[iPosParent].nEndL;
 CString csName;
 while ( csName.IsEmpty() )
 {
  // Look for left angle bracket of start tag
  m_aPos[iPos].nStartL = token.nNext;
  if ( ! x_FindChar( m_aPos[iPos].nStartL, _T('<') ) )
   return x_ParseError( _T("Element tag not found") );

  // Set parent's End tag to start looking from here (or later)
  m_aPos[iPosParent].nEndL = m_aPos[iPos].nStartL;

  // Determine whether this is an element, comment or version tag
  LPCTSTR szEndOfTag = NULL;
  token.nNext = m_aPos[iPos].nStartL + 1;
  if ( x_FindToken( token ) )
  {
   if ( token.bIsString )
    return x_ParseError( _T("Tag starts with quote") );
   TCHAR cFirstChar = m_csDoc[token.nL];
   if ( cFirstChar == _T('?') )
    szEndOfTag = _T("?>"); // version
   else if ( cFirstChar == _T('!') )
   {
    TCHAR cSecondChar = 0;
    if ( token.nL+1 < m_csDoc.GetLength() )
     cSecondChar = m_csDoc[token.nL+1];
    if ( cSecondChar == _T('[') )
     szEndOfTag = _T("]]>"); // CDATA section
    else if ( cSecondChar == _T('-') )
     szEndOfTag = _T("-->"); // comment
    else
     szEndOfTag = _T(">"); // DTD
   }
   else if ( cFirstChar != _T('/') )
   {
    csName = x_GetToken( token );
    szEndOfTag = _T(">");
   }
   else
    return x_ReleasePos(); // probably end tag of parent
  }
  else
   return x_ParseError( _T("Abrupt end within tag") );

  // Look for end of tag
  token.nNext = m_csDoc.Find( szEndOfTag, token.nNext );
  if ( token.nNext == -1 )
   return x_ParseError( _T("End of tag not found") );
 }
 m_aPos[iPos].nStartR = token.nNext;

 // Is ending mark within start tag, i.e. empty element?
 if ( m_csDoc[m_aPos[iPos].nStartR-1] == _T('/') )
 {
  // Empty element
  // Close tag left is set to ending mark, and right to open tag right
  m_aPos[iPos].nEndL = m_aPos[iPos].nStartR-1;
  m_aPos[iPos].nEndR = m_aPos[iPos].nStartR;
 }
 else // look for end tag
 {
  // Element probably has contents
  // Determine where to start looking for left angle bracket of end tag
  // This is done by recursively parsing the contents of this element
  int iInner, iInnerPrev = 0;
  m_aPos[iPos].nEndL = m_aPos[iPos].nStartR + 1;
  while ( (iInner = x_ParseElem( iPos )) > 0 )
  {
   // Set links to iInner
   if ( iInnerPrev )
    m_aPos[iInnerPrev].iElemNext = iInner;
   else
    m_aPos[iPos].iElemChild = iInner;
   iInnerPrev = iInner;

   // Set offset to reflect child
   m_aPos[iPos].nEndL = m_aPos[iInner].nEndR + 1;
  }
  if ( iInner == -1 )
   return -1;

  // Look for left angle bracket of end tag
  if ( ! x_FindChar( m_aPos[iPos].nEndL, _T('<') ) )
   return x_ParseError( _T("End tag of %s element not found"), csName );

  // Look through tokens of end tag
  token.nNext = m_aPos[iPos].nEndL + 1;
  int nTokenCount = 0;
  while ( x_FindToken( token ) )
  {
   ++nTokenCount;
   if ( ! token.bIsString )
   {
    // Is first token not an end slash mark?
    if ( nTokenCount == 1 && m_csDoc[token.nL] != _T('/') )
     return x_ParseError( _T("Expecting end tag of element %s"), csName );

    else if ( nTokenCount == 2 && csName != x_GetToken( token ) )
     return x_ParseError( _T("End tag does not correspond to %s"), csName );

    // Else is it a right angle bracket?
    else if ( m_csDoc[token.nL] == _T('>') )
     break;
   }
  }

  // Was a right angle bracket not found?
  if ( ! token.IsValid() || nTokenCount < 2 )
   return x_ParseError( _T("End tag not completed for element %s"), csName );
  m_aPos[iPos].nEndR = token.nL;
 }

 // Successfully found positions of angle brackets
 m_aPos[iPos].nNext = m_aPos[iPos].nEndR;
 x_FindChar( m_aPos[iPos].nNext, _T('<') );
 return iPos;
}

bool CMarkup::x_FindChar( int&n, _TCHAR c ) const
{
 // Look for char c starting at n, and set n to point to it
 // c is always the first char of a multi-byte char
 // Return false if not found before end of document
 LPCTSTR szDoc = (LPCTSTR)m_csDoc;
 while ( szDoc[n] && szDoc[n] != c )
  n += _tclen( &szDoc[n] );
 if ( ! szDoc[n] )
  return false;
 return true;
}

bool CMarkup::x_FindToken( CMarkup::TokenPos& token ) const
{
 // Starting at token.nNext, find the next token
 // upon successful return, token.nNext points after the retrieved token
 LPCTSTR szDoc = (LPCTSTR)m_csDoc;
 int n = token.nNext;

 // Statically defined CStrings for whitespace and special chars
 static CString csWhitespace = _T(" \t\n\r");
 static CString csSpecial = _T("<>=\\/?!");

 // By-pass leading whitespace
 while ( szDoc[n] && csWhitespace.Find(szDoc[n]) > -1 )
  ++n;

 // Are we still within the document?
 token.bIsString = false;
 if ( szDoc[n] )
 {
  // Is it an opening quote?
  if ( szDoc[n] == _T('\"') )
  {
   // Move past opening quote
   ++n;
   token.nL = n;

   // Look for closing quote
   x_FindChar( n, _T('\"') );

   // Set right to before closing quote
   token.nR = n-1;

   // Set n past closing quote unless at end of document
   if ( szDoc[n] )
    ++n;

   // Set flag
   token.bIsString = true;
  }
  else
  {
   // Go until special char or whitespace
   token.nL = n;
   while ( szDoc[n] &&
    csSpecial.Find(m_csDoc[n]) == -1 &&
    csWhitespace.Find(m_csDoc[n]) == -1
    )
    n += _tclen(&szDoc[n]);

   // Adjust end position if it is one special char
   if ( n == token.nL )
    ++n; // it is a special char
   token.nR = n-1;
  }
 }

 token.nNext = n;
 if ( ! szDoc[n] )
  return false;

 // nNext points to one past last char of token
 return true;
}

CString CMarkup::x_GetToken( const CMarkup::TokenPos& token ) const
{
 // The token contains indexes into the document identifying a small substring
 // Build the substring from those indexes and return it
 if ( ! token.IsValid() )
  return _T("");
 return m_csDoc.Mid( token.nL,
  token.nR - token.nL + ((token.nR<m_csDoc.GetLength())? 1:0) );
}

CString CMarkup::x_GetTagName( int iPos ) const
{
 // Return the tag name at specified element
 TokenPos token;
 token.nNext = m_aPos[iPos].nStartL + 1;
 if ( ! iPos || ! x_FindToken( token ) )
  return _T("");

 // Return substring of document
 return x_GetToken( token );
}

bool CMarkup::x_FindAttrib( CMarkup::TokenPos& token, LPCTSTR szAttrib ) const
{
 // If szAttrib is NULL find next attrib, otherwise find named attrib
 // Return true if found
 int nAttrib = 0;
 for ( int nCount = 0; x_FindToken(token); ++nCount )
 {
  if ( ! token.bIsString )
  {
   // Is it the right angle bracket?
   if ( m_csDoc[token.nL] == _T('>') || m_csDoc[token.nL] == _T('/') )
    break; // attrib not found

   // Equal sign
   if ( m_csDoc[token.nL] == _T('=') )
    continue;

   // Potential attribute
   if ( ! nAttrib && nCount )
   {
    // Attribute name search?
    if ( ! szAttrib || ! szAttrib[0] )
     return true; // return with token at attrib name

    // Compare szAttrib
    if ( x_GetToken(token) == szAttrib )
     nAttrib = nCount;
   }
  }
  else if ( nAttrib && nCount == nAttrib + 2 )
  {
   return true;
  }
 }

 // Not found
 return false;
}

CString CMarkup::x_GetAttrib( int iPos, LPCTSTR szAttrib ) const
{
 // Return the value of the attrib at specified element
 TokenPos token;
 token.nNext = m_aPos[iPos].nStartL + 1;
 if ( szAttrib && x_FindAttrib( token, szAttrib ) )
  return x_TextFromDoc( token.nL, token.nR - ((token.nR<m_csDoc.GetLength())?0:1) );
 return _T("");
}

CString CMarkup::x_GetData( int iPos ) const
{
 // Return a string representing data between start and end tag
 // Return empty string if there are any children elements
 if ( ! m_aPos[iPos].iElemChild && ! m_aPos[iPos].IsEmptyElement() )
 {
  // See if it is a CDATA section
  TokenPos token;
  token.nNext = m_aPos[iPos].nStartR+1;
  if ( x_FindToken( token ) && m_csDoc[token.nL] == _T('<')
    && token.nL + 11 < m_aPos[iPos].nEndL
    && _tcsncmp( &((LPCTSTR)m_csDoc)[token.nL+1], _T("![CDATA["), 8 ) == 0 )
  {
   int nEndCDATA = m_csDoc.Find( _T("]]>"), token.nNext );
   if ( nEndCDATA != -1 && nEndCDATA < m_aPos[iPos].nEndL )
   {
    return m_csDoc.Mid( token.nL+9, nEndCDATA-token.nL-9 );
   }
  }
  return x_TextFromDoc( m_aPos[iPos].nStartR+1, m_aPos[iPos].nEndL-1 );
 }
 return "";
}

CString CMarkup::x_TextToDoc( LPCTSTR szText, bool bAttrib ) const
{
 // Convert text as seen outside XML document to XML friendly
 // replacing special characters with ampersand escape codes
 // E.g. convert "6>7" to "6&gt;7"
 //
 // &lt;   less than
 // &amp;  ampersand
 // &gt;   greater than
 //
 // and for attributes:
 //
 // &apos; apostrophe or single quote
 // &quot; double quote
 //
 static _TCHAR* szaReplace[] = { _T("&lt;"),_T("&amp;"),_T("&gt;"),_T("&apos;"),_T("&quot;") };
 const _TCHAR* pFind = bAttrib?_T("<&>\'\""):_T("<&>");
 CString csText;
 const _TCHAR* pSource = szText;
 int nDestSize = _tcslen(pSource);
 nDestSize += nDestSize / 10 + 7;
 _TCHAR* pDest = csText.GetBuffer(nDestSize);
 int nLen = 0;
 _TCHAR cSource = *pSource;
 _TCHAR* pFound;
 while ( cSource )
 {
  if ( nLen > nDestSize - 6 )
  {
   csText.ReleaseBuffer(nLen);
   nDestSize *= 2;
   pDest = csText.GetBuffer(nDestSize);
  }
  if ( (pFound=_tcschr(pFind,cSource)) != NULL )
  {
   pFound = szaReplace[pFound-pFind];
   _tcscpy(&pDest[nLen],pFound);
   nLen += _tcslen(pFound);
  }
  else
  {
   _tccpy( &pDest[nLen], pSource );
   ++nLen;
  }
  pSource += _tclen( pSource );
  cSource = *pSource;
 }
 csText.ReleaseBuffer(nLen);
 return csText;
}

CString CMarkup::x_TextFromDoc( int nLeft, int nRight ) const
{
 // Convert XML friendly text to text as seen outside XML document
 // replacing ampersand escape codes with special characters
 // E.g. convert "6&gt;7" to "6>7"
 //
 // Conveniently the result is always the same or shorter in length
 //
 static _TCHAR* szaCode[] = { _T("lt;"),_T("amp;"),_T("gt;"),_T("apos;"),_T("quot;") };
 static int anCodeLen[] = { 3,4,3,5,5 };
 static _TCHAR* szSymbol = _T("<&>\'\"");
 CString csText;
 const _TCHAR* pSource = m_csDoc;
 int nDestSize = nRight - nLeft + 1;
 _TCHAR* pDest = csText.GetBuffer(nDestSize);
 int nLen = 0;
 int nCharLen;
 int nChar = nLeft;
 while ( nChar <= nRight )
 {
  if ( pSource[nChar] == _T('&') )
  {
   // Look for matching &code;
   for ( int nMatch = 0; nMatch < 5; ++nMatch )
   {
    if ( nChar <= nRight - anCodeLen[nMatch]
     && _tcsncmp(szaCode[nMatch],&pSource[nChar+1],anCodeLen[nMatch]) == 0 )
    {
     pDest[nLen++] = szSymbol[nMatch];
     nChar += anCodeLen[nMatch] + 1;
     break;
    }
   }

   // If no match is found it means XML doc is invalid
   // no devastating harm done, ampersand code will just be left in result
   if ( nMatch == 5 )
   {
    pDest[nLen++] = _T('&');
    ++nChar;
   }
  }
  else
  {
   nCharLen = _tclen(&pSource[nChar]);
   _tccpy( &pDest[nLen], &pSource[nChar] );
   nLen += nCharLen;
   nChar += nCharLen;
  }
 }
 csText.ReleaseBuffer(nLen);
 return csText;
}

void CMarkup::x_DocChange( int nLeft, int nReplace, const CString& csInsert )
{
 // Insert csInsert int m_csDoc at nLeft replacing nReplace chars
 // Do this with only one buffer reallocation if it grows
 //
 int nDocLength = m_csDoc.GetLength();
 int nInsLength = csInsert.GetLength();

 // Make sure nLeft and nReplace are within bounds
 nLeft = max( 0, min( nLeft, nDocLength ) );
 nReplace = max( 0, min( nReplace, nDocLength-nLeft ) );

 // Get pointer to buffer with enough room
 int nNewLength = nInsLength + nDocLength - nReplace;
 int nBufferLen = nNewLength;
 _TCHAR* pDoc = m_csDoc.GetBuffer( nBufferLen );

 // Move part of old doc that goes after insert
 if ( nLeft+nReplace < nDocLength )
  memmove( &pDoc[nLeft+nInsLength], &pDoc[nLeft+nReplace], (nDocLength-nLeft-nReplace)*sizeof(_TCHAR) );

 // Copy insert
 memcpy( &pDoc[nLeft], csInsert, nInsLength*sizeof(_TCHAR) );

 // Release
 m_csDoc.ReleaseBuffer( nNewLength );
}

void CMarkup::x_Adjust( int iPos, int nShift )
{
 // Loop through affected elements and adjust indexes
 // Does not affect iPos itself
 // Algorithm:
 // 1. update next siblings and all their children
 // 2. then go up a level update end points and to step 1
 int iPosTop = m_aPos[iPos].iElemParent;
 while ( iPos )
 {
  // Were we at containing parent of affected position?
  bool bPosTop = false;
  if ( iPos == iPosTop )
  {
   // Move iPosTop up one towards root
   iPosTop = m_aPos[iPos].iElemParent;
   bPosTop = true;
  }

  // Traverse to the next update position
  if ( ! bPosTop && m_aPos[iPos].iElemChild )
  {
   // Depth first
   iPos = m_aPos[iPos].iElemChild;
  }
  else if ( m_aPos[iPos].iElemNext )
  {
   iPos = m_aPos[iPos].iElemNext;
  }
  else
  {
   // Look for next sibling of a parent of iPos
   // When going back up, parents have already been done except iPosTop
   while ( (iPos=m_aPos[iPos].iElemParent) != 0 && iPos != iPosTop )
    if ( m_aPos[iPos].iElemNext )
    {
     iPos = m_aPos[iPos].iElemNext;
     break;
    }
  }

  // Shift indexes at iPos
  if ( iPos != iPosTop )
  {
   // Move the start tag indexes
   // Don't do this for containing parent tag
   m_aPos[iPos].nStartL += nShift;
   m_aPos[iPos].nStartR += nShift;
  }
  // Move end tag indexes
  m_aPos[iPos].nEndL += nShift;
  m_aPos[iPos].nEndR += nShift;
  m_aPos[iPos].nNext += nShift;
 }
}

int CMarkup::x_Add( int iPosParent, int iPosBefore, LPCTSTR szName, LPCTSTR szValue )
{
 // Create element and modify positions of affected elements
 // if iPosBefore is NULL, insert as first element under parent
 // If no szValue is specified, an empty element is created
 // i.e. either <NAME>value</NAME> or <NAME/>
 //
 int iPos = x_GetFreePos();
 bool bEmptyParent = false;
 if ( iPosBefore )
 {
  // Follow iPosBefore
  m_aPos[iPos].nStartL = m_aPos[iPosBefore].nNext;
 }
 else if ( m_aPos[iPosParent].iElemChild )
 {
  // Insert before first child of parent
  m_aPos[iPos].nStartL = m_aPos[m_aPos[iPosParent].iElemChild].nStartL;
 }
 else if ( m_aPos[iPosParent].IsEmptyElement() )
 {
  // Parent has no separate end tag
  m_aPos[iPos].nStartL = m_aPos[iPosParent].nStartR + 2;
  bEmptyParent = true;
 }
 else
 {
  // Parent has content, but no children
  m_aPos[iPos].nStartL = m_aPos[iPosParent].nEndL;
 }

 // Set links
 m_aPos[iPos].iElemParent = iPosParent;
 m_aPos[iPos].iElemChild = 0;
 if ( iPosBefore )
 {
  m_aPos[iPos].iElemNext = m_aPos[iPosBefore].iElemNext;
  m_aPos[iPosBefore].iElemNext = iPos;
 }
 else
 {
  m_aPos[iPos].iElemNext = m_aPos[iPosParent].iElemChild;
  m_aPos[iPosParent].iElemChild = iPos;
 }

 // Create string for insert
 CString csInsert;
 int nLenName = _tcslen(szName);
 int nLenValue = szValue? _tcslen(szValue) : 0;
 if ( ! nLenValue )
 {
  // <NAME/> empty element
  csInsert.Format( _T("<%s/>\r\n"), szName );
  m_aPos[iPos].nStartR = m_aPos[iPos].nStartL + nLenName + 2;
  m_aPos[iPos].nEndL = m_aPos[iPos].nStartR - 1;
  m_aPos[iPos].nEndR = m_aPos[iPos].nEndL + 1;
  m_aPos[iPos].nNext = m_aPos[iPos].nEndR + 3;
 }
 else
 {
  // <NAME>value</NAME>
  CString csValue = x_TextToDoc( szValue );
  nLenValue = csValue.GetLength();
  csInsert.Format( _T("<%s>%s</%s>\r\n"), szName, csValue, szName );
  m_aPos[iPos].nStartR = m_aPos[iPos].nStartL + nLenName + 1;
  m_aPos[iPos].nEndL = m_aPos[iPos].nStartR + nLenValue + 1;
  m_aPos[iPos].nEndR = m_aPos[iPos].nEndL + nLenName + 2;
  m_aPos[iPos].nNext = m_aPos[iPos].nEndR + 3;
 }

 // Insert
 int nReplace = 0, nLeft = m_aPos[iPos].nStartL;
 if ( bEmptyParent )
 {
  CString csParentTagName = x_GetTagName(iPosParent);
  csInsert = _T(">\r\n") + csInsert + _T("</") + csParentTagName;
  nLeft -= 3;
  nReplace = 1;
  // x_Adjust is going to update all affected indexes by one amount
  // This will satisfy all except the empty parent
  // Here we pre-adjust for the empty parent
  // The empty tag slash is removed
  m_aPos[iPosParent].nStartR -= 1;
  // For the newly created end tag, see the following example:
  // <A/> (len 4) becomes <A><B/></A> (len 11)
  // In x_Adjust everything will be adjusted 11 - 4 = 7
  // But the nEndL of element A should only be adjusted 5
  m_aPos[iPosParent].nEndL -= (csParentTagName.GetLength() + 1);
 }
 x_DocChange( nLeft, nReplace, csInsert );
 x_Adjust( iPos, csInsert.GetLength() - nReplace );

 // Return the index of the new element
 return iPos;
}

int CMarkup::x_AddAttrib( int iPos, LPCTSTR szAttrib, LPCTSTR szValue )
{
 // Add attribute to iPos element
 CString csInsert;
 if ( iPos )
 {
  // Insert string taking into account whether it is a single tag
  CString csValue = x_TextToDoc( szValue, true );
  csInsert.Format( _T(" %s=\"%s\""), szAttrib, csValue );
  int nL = m_aPos[iPos].nStartR - (m_aPos[iPos].IsEmptyElement()?1:0);
  x_DocChange( nL, 0, csInsert );

  int nLen = csInsert.GetLength();
  m_aPos[iPos].nStartR += nLen;
  m_aPos[iPos].nEndL += nLen;
  m_aPos[iPos].nEndR += nLen;
  m_aPos[iPos].nNext += nLen;
  x_Adjust( iPos, nLen );
 }
 return csInsert.GetLength();
}

不知道是不是这个。


--  作者:振臂
--  发布时间:4/27/2006 10:14:00 PM

--  
二楼的,能发一个给我吗?
E-mail: stephen99720@sohu.com
谢谢!
--  作者:Afanty
--  发布时间:4/30/2006 3:54:00 PM

--  
哈,我也要啊! fc4503@163.com
W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
296.875ms