新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> XML编辑器,XML解析器,XML开发环境
    [返回] 中文XML论坛 - 专业的XML技术讨论区XML.ORG.CN讨论区 - XML技术『 XML工具及XML开发环境 』 → 哪位有C或C++编写xml解析器的源代码 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 76123 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 哪位有C或C++编写xml解析器的源代码 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     zhu_ruixian 帅哥哟,离线,有人找我吗?射手座1983-12-2
      
      
      威望:2
      等级:大二期末(Java考了96分!)
      文章:406
      积分:3471
      门派:W3CHINA.ORG
      注册:2006/3/30

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给zhu_ruixian发送一个短消息 把zhu_ruixian加入好友 查看zhu_ruixian的个人资料 搜索zhu_ruixian在『 XML工具及XML开发环境 』的所有贴子 引用回复这个贴子 回复这个贴子 查看zhu_ruixian的博客41
    发贴心情 

    // 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();
    }

    不知道是不是这个。

    ----------------------------------------------
    为什么总是索取的人多,奉献的人少...

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/4/27 12:40:00
     
     振臂 帅哥哟,离线,有人找我吗?
      
      
      等级:大一(高数修炼中)
      文章:8
      积分:114
      门派:XML.ORG.CN
      注册:2006/3/18

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给振臂发送一个短消息 把振臂加入好友 查看振臂的个人资料 搜索振臂在『 XML工具及XML开发环境 』的所有贴子 引用回复这个贴子 回复这个贴子 查看振臂的博客42
    发贴心情 
    二楼的,能发一个给我吗?
    E-mail: stephen99720@sohu.com
    谢谢!
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/4/27 22:14:00
     
     Afanty 帅哥哟,离线,有人找我吗?白羊座1982-4-1
      
      
      等级:大二(研究汇编)
      文章:45
      积分:253
      门派:XML.ORG.CN
      注册:2006/3/29

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给Afanty发送一个短消息 把Afanty加入好友 查看Afanty的个人资料 搜索Afanty在『 XML工具及XML开发环境 』的所有贴子 引用回复这个贴子 回复这个贴子 查看Afanty的博客43
    发贴心情 
    哈,我也要啊! fc4503@163.com

    ----------------------------------------------
    雅俗共赏,宁缺勿滥!

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/4/30 15:54:00
     
     GoogleAdSense白羊座1982-4-1
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 XML工具及XML开发环境 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/5/6 9:09:01

    本主题贴数43,分页:[1] ... [2] [3] [4] [5]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    1,750.000ms