📄 xmlparse.cpp
字号:
}
else if ( nParseFlags )
{
if ( nParseFlags & PD_TEXTORWS )
{
if ( cD == _T('<') )
{
nR = (int)(pDoc - token.szDoc) - 1;
nNodeType = MNT_WHITESPACE;
break;
}
else if ( ! _tcschr(_T(" \t\n\r"),(_TCHAR)cD) )
{
nParseFlags ^= PD_TEXTORWS;
FINDNODETYPE( _T("<"), MNT_TEXT, 0 )
}
}
else if ( nParseFlags & PD_OPENTAG )
{
nParseFlags ^= PD_OPENTAG;
if ( cD > 0x60 || ( cD > 0x40 && cD < 0x5b ) || cD == 0x5f || cD == 0x3a )
FINDNODETYPE( _T(">"), MNT_ELEMENT, 1 )
else if ( cD == _T('/') )
FINDNODETYPE( _T(">"), 0, 2 )
else if ( cD == _T('!') )
nParseFlags |= PD_BANG;
else if ( cD == _T('?') )
FINDNODETYPE( _T("?>"), MNT_PROCESSING_INSTRUCTION, 2 )
else
FINDNODEBAD( _T("tag name character") )
}
else if ( nParseFlags & PD_BANG )
{
nParseFlags ^= PD_BANG;
if ( cD == _T('-') )
nParseFlags |= PD_DASH;
else if ( cD == _T('[') && !(nParseFlags & PD_DOCTYPE) )
nParseFlags |= PD_BRACKET;
else if ( cD == _T('D') && !(nParseFlags & PD_DOCTYPE) )
nParseFlags |= PD_DOCTYPE;
else if ( _tcschr(_T("EAN"),(_TCHAR)cD) ) // <!ELEMENT ATTLIST ENTITY NOTATION
FINDNODETYPE( _T(">"), MNT_DOCUMENT_TYPE, 0 )
else
FINDNODEBAD( _T("! tag") )
}
else if ( nParseFlags & PD_DASH )
{
nParseFlags ^= PD_DASH;
if ( cD == _T('-') )
FINDNODETYPE( _T("-->"), MNT_COMMENT, 0 )
else
FINDNODEBAD( _T("comment tag") )
}
else if ( nParseFlags & PD_BRACKET )
{
nParseFlags ^= PD_BRACKET;
if ( cD == _T('C') )
FINDNODETYPE( _T("]]>"), MNT_CDATA_SECTION, 0 )
else
FINDNODEBAD( _T("tag") )
}
else if ( nParseFlags & PD_DOCTYPE )
{
if ( cD == _T('<') )
nParseFlags |= PD_OPENTAG;
else if ( cD == _T('>') )
{
nR = (int)(pDoc - token.szDoc);
nNodeType = MNT_DOCUMENT_TYPE;
break;
}
}
}
else if ( cD == _T('<') )
{
nParseFlags |= PD_OPENTAG;
}
else
{
nNodeType = MNT_WHITESPACE;
if ( _tcschr(_T(" \t\n\r"),(_TCHAR)cD) )
nParseFlags |= PD_TEXTORWS;
else
FINDNODETYPE( _T("<"), MNT_TEXT, 0 )
}
pDoc += _tclen( pDoc );
}
token.nNext = nR + 1;
node.nLength = token.nNext - node.nStart;
node.nNodeType = nNodeType;
return nNodeType;
}
string CXMLParse::x_GetPath( int iPos ) const
{
CString strPath;
while ( iPos )
{
CString strTagName = x_GetTagName( iPos ).c_str();
int iPosParent = m_aPos[iPos].iElemParent;
int iPosSib = 0;
int nCount = 0;
while ( iPosSib != iPos )
{
iPosSib = x_FindElem( iPosParent, iPosSib, strTagName );
++nCount;
}
if ( nCount > 1 )
{
_TCHAR szPred[25];
_stprintf( szPred, _T("[%d]"), nCount );
strPath = _T("/") + strTagName + szPred + strPath;
}
else
strPath = _T("/") + strTagName + strPath;
iPos = iPosParent;
}
return string(strPath);
}
string CXMLParse::x_GetTagName( int iPos ) const
{
// Return the tag name at specified element
TokenPos token( m_strDoc, m_nFlags );
token.nNext = m_aPos[iPos].nStart + 1;
if ( ! iPos || ! x_FindName( token ) )
return _T("");
// Return substring of document
return x_GetToken( token );
}
bool CXMLParse::x_FindAttrib( CXMLParse::TokenPos& token, const char * szAttrib, int n/*=0*/ )
{
// Return true if found, otherwise false and token.nNext is new insertion point
// If szAttrib is NULL find attrib n and leave token at attrib name
// If szAttrib is given, find matching attrib and leave token at value
// support non-well-formed attributes e.g. href=/advanced_search?hl=en, nowrap
// token also holds start and length of preceeding whitespace to support remove
//
int nPreSpaceStart;
int nPreSpaceLength;
int nChar;
_TCHAR cFirstChar;
LPCTSTR szDoc = token.szDoc;
int nAttrib = -1; // starts at tag name
int nFoundAttribNameR = 0;
bool bAfterEqual = false;
while ( 1 )
{
// Starting at token.nNext, bypass whitespace and find the next token
nChar = token.nNext;
nPreSpaceStart = nChar;
if ( ! x_FindAny(szDoc,nChar) )
break;
nPreSpaceLength = nChar - nPreSpaceStart;
// Is it an opening quote?
cFirstChar = szDoc[nChar];
if ( cFirstChar == _T('\"') || cFirstChar == _T('\'') )
{
token.nTokenFlags |= MNF_QUOTED;
// Move past opening quote
++nChar;
token.nL = nChar;
// Look for closing quote
while ( szDoc[nChar] && szDoc[nChar] != cFirstChar )
nChar += (int)_tclen( &szDoc[nChar] );
// Set right to before closing quote
token.nR = nChar - 1;
// Set nChar past closing quote unless at end of document
if ( szDoc[nChar] )
++nChar;
}
else
{
token.nTokenFlags &= ~MNF_QUOTED;
// Go until special char or whitespace
token.nL = nChar;
if ( bAfterEqual )
{
while ( szDoc[nChar] && ! _tcschr(_T(" \t\n\r>"),szDoc[nChar]) )
nChar += (int)_tclen( &szDoc[nChar] );
}
else
{
while ( szDoc[nChar] && ! _tcschr(_T("= \t\n\r>/?"),szDoc[nChar]) )
nChar += (int)_tclen( &szDoc[nChar] );
}
// Adjust end position if it is one special char
if ( nChar == token.nL )
++nChar; // it is a special char
token.nR = nChar - 1;
}
// nNext points to one past last char of token
token.nNext = nChar;
if ( ! bAfterEqual && ! (token.nTokenFlags&MNF_QUOTED) )
{
// Is it an equal sign?
_TCHAR cChar = szDoc[token.nL];
if ( cChar == _T('=') )
{
bAfterEqual = true;
continue;
}
// Is it the right angle bracket?
if ( cChar == _T('>') || cChar == _T('/') || cChar == _T('?') )
{
token.nNext = nPreSpaceStart;
break; // attrib not found
}
if ( nFoundAttribNameR )
break;
// Attribute name
if ( nAttrib != -1 )
{
if ( ! szAttrib )
{
if ( nAttrib == n )
return true; // found by number
}
else if ( token.Match(szAttrib) )
{
// Matched attrib name, go forward to value
nFoundAttribNameR = token.nR;
token.nPreSpaceStart = nPreSpaceStart;
token.nPreSpaceLength = nPreSpaceLength;
}
}
++nAttrib;
}
else if ( nFoundAttribNameR )
break;
bAfterEqual = false;
}
if ( nFoundAttribNameR )
{
if ( ! bAfterEqual )
{
// when attribute has no value the value is the attribute name
token.nL = token.nPreSpaceStart + token.nPreSpaceLength;
token.nR = nFoundAttribNameR;
token.nNext = nFoundAttribNameR + 1;
}
return true; // found by name
}
return false; // not found
}
std::string CXMLParse::x_GetAttrib( int iPos, const char * szAttrib ) const
{
// Return the value of the attrib
TokenPos token( m_strDoc, m_nFlags );
if ( iPos && m_nNodeType == MNT_ELEMENT )
token.nNext = m_aPos[iPos].nStart + 1;
else if ( iPos == m_iPos && m_nNodeLength && m_nNodeType == MNT_PROCESSING_INSTRUCTION )
token.nNext = m_nNodeOffset + 2;
else
return _T("");
if ( szAttrib && x_FindAttrib( token, szAttrib ) )
return UnescapeText( &token.szDoc[token.nL], token.Length() );
return _T("");
}
bool CXMLParse::x_SetAttrib( int iPos, const char * szAttrib, __int64 nValue)
{
_TCHAR szVal[25];
_stprintf( szVal, _T("%I64d"), nValue );
return x_SetAttrib( iPos, szAttrib, szVal );
}
bool CXMLParse::x_SetAttrib( int iPos, const char * szAttrib, int nValue )
{
// Convert integer to string
_TCHAR szVal[25];
_stprintf( szVal, _T("%d"), nValue );
return x_SetAttrib( iPos, szAttrib, szVal );
}
bool CXMLParse::x_SetAttrib( int iPos, const char * szAttrib, const char * szValue )
{
// Set attribute in iPos element
TokenPos token( m_strDoc, m_nFlags );
if ( iPos && m_nNodeType == MNT_ELEMENT )
token.nNext = m_aPos[iPos].nStart + 1;
else if ( iPos == m_iPos && m_nNodeLength && m_nNodeType == MNT_PROCESSING_INSTRUCTION )
token.nNext = m_nNodeOffset + 2;
else
return false;
// Create insertion text depending on whether attribute already exists
// Decision: for empty value leaving attrib="" instead of removing attrib
int nReplace = 0;
int nInsertAt;
CString strInsert;
strInsert += x_ATTRIBQUOTE;
strInsert += EscapeText( szValue, MNF_ESCAPEQUOTES ).c_str();
strInsert += x_ATTRIBQUOTE;
if ( x_FindAttrib( token, szAttrib ) )
{
// Replace value
nInsertAt = token.nL - ((token.nTokenFlags&MNF_QUOTED)?1:0);
nReplace = token.Length() + ((token.nTokenFlags&MNF_QUOTED)?2:0);
}
else
{
// Insert string name value pair
CString strFormat;
strFormat = _T(" ");
strFormat += szAttrib;
strFormat += _T("=");
strFormat += strInsert;
strInsert = strFormat;
nInsertAt = token.nNext;
}
x_DocChange( nInsertAt, nReplace, strInsert );
int nAdjust = strInsert.GetLength() - nReplace;
if ( m_nNodeType == MNT_PROCESSING_INSTRUCTION )
{
x_AdjustForNode( m_iPosParent, m_iPos, nAdjust );
m_nNodeLength += nAdjust;
return true;
}
m_aPos[iPos].AdjustStartTagLen( nAdjust );
m_aPos[iPos].nLength += nAdjust;
x_Adjust( iPos, nAdjust );
return true;
}
bool CXMLParse::x_CreateNode( CString& strNode, int nNodeType, const char * szText )
{
// Set strNode based on nNodeType and szData
// Return false if szData would jeopardize well-formed document
//
switch ( nNodeType )
{
case MNT_PROCESSING_INSTRUCTION:
strNode = "<?";
strNode += szText;
strNode += "?>";
break;
case MNT_COMMENT:
strNode = "<!--";
strNode += szText;
strNode += "-->";
break;
case MNT_ELEMENT:
strNode = "<";
strNode += szText;
strNode += "/>";
break;
case MNT_TEXT:
case MNT_WHITESPACE:
strNode = EscapeText( szText ).c_str();
break;
case MNT_DOCUMENT_TYPE:
strNode = szText;
break;
case MNT_LONE_END_TAG:
return false;
case MNT_CDATA_SECTION:
if ( _tcsstr(szText,_T("]]>")) != NULL )
return false;
strNode = "<![CDATA[";
strNode += szText;
strNode += "]]>";
break;
}
return true;
}
CString CXMLParse::x_EncodeCDATASection( const char * szData )
{
// Split CDATA Sections if there are any end delimiters
CString strData = _T("<![CDATA[");
LPCTSTR pszNextStart = szData;
LPCTSTR pszEnd = _tcsstr( szData, _T("]]>") );
while ( pszEnd )
{
strData += CString( pszNextStart, (int)(pszEnd - pszNextStart) );
strData += _T("]]]]><![CDATA[>");
pszNextStart = pszEnd + 3;
pszEnd = _tcsstr( pszNextStart, _T("]]>") );
}
strData += pszNextStart;
strData += _T("]]>");
return strData;
}
bool CXMLParse::x_SetData( int iPos, int nValue )
{
// Convert integer to string
_TCHAR szVal[25];
_stprintf( szVal, _T("%d"), nValue );
return x_SetData( iPos, szVal, 0 );
}
bool CXMLParse::x_SetData( int iPos, const char * szData, int nFlags )
{
// Set data at specified position
// if nFlags==1, set content of element to a CDATA Section
CString strInsert;
if ( iPos == m_iPos && m_nNodeLength )
{
// Not an element
if ( ! x_CreateNode(strInsert, m_nNodeType, szData) )
return false;
x_DocChange( m_nNodeOffset, m_nNodeLength, strInsert );
x_AdjustForNode( m_iPosParent, iPos, strInsert.GetLength() - m_nNodeLength );
m_nNodeLength = strInsert.GetLength();
return true;
}
// Set data in iPos element
if ( ! iPos || m_aPos[iPos].iElemChild )
return false;
// Build strInsert from szData based on nFlags
if ( nFlags & MNF_WITHCDATA )
strInsert = x_EncodeCDATASection( szData );
else
strInsert = EscapeText( szData, nFlags ).c_str();
// Insert
NodePos node( MNF_WITHNOLINES|MNF_REPLACE );
node.strMeta = strInsert;
int iPosBefore = 0;
int nReplace = x_InsertNew( iPos, iPosBefore, node );
int nAdjust = node.strMeta.GetLength() - nReplace;
x_Adjust( iPos, nAdjust );
m_aPos[iPos].nLength += nAdjust;
if ( m_aPos[iPos].nFlags & MNF_ILLDATA )
m_aPos[iPos].nFlags &= ~MNF_ILLDATA;
return true;
}
string CXMLParse::x_GetData( int iPos ) const
{
if ( iPos == m_iPos && m_nNodeLength )
{
if ( m_nNodeType == MNT_COMMENT )
return string(m_strDoc.Mid( m_nNodeOffset+4, m_nNodeLength-7 ));
else if ( m_nNodeType == MNT_PROCESSING_INSTRUCTION )
return string(m_strDoc.Mid( m_nNodeOffset+2, m_nNodeLength-4 ));
else if ( m_nNodeType == MNT_CDATA_SECTION )
return string(m_strDoc.Mid( m_nNodeOffset+9, m_nNodeLength-12 ));
else if ( m_nNodeType == MNT_TEXT )
return UnescapeText( &((LPCTSTR)m_strDoc)[m_nNodeOffset], m_nNodeLength );
else if ( m_nNodeType == MNT_LONE_END_TAG )
return string(m_strDoc.Mid( m_nNodeOffset+2, m_nNodeLength-3 ));
else
return string(m_strDoc.Mid( m_nNodeOffset, m_nNodeLength ));
}
// Return a string representing data between start and end tag
// Return empty string if there are any children elements
CString strData;
if ( ! m_aPos[iPos].iElemChild && ! m_aPos[iPos].IsEmptyElement() )
{
// Quick scan for any tags inside content
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -