📄 markupstl.cpp
字号:
} // Was a right angle bracket not found? if ( ! token.szDoc[token.nL] || nTokenCount < 2 ) return x_ParseError( "End tag not completed for element %s", strName.c_str() ); m_aPos[iPos].nEndR = token.nL; } // Successfully parsed element (and contained elements) return iPos;}bool CMarkupSTL::x_FindChar( const char* szDoc, int& nChar, char c ){ // static function const char* pChar = &szDoc[nChar]; while ( *pChar && *pChar != c ) pChar += 1; nChar = pChar - szDoc; if ( ! *pChar ) return false; /* while ( szDoc[nChar] && szDoc[nChar] != c ) nChar += _tclen( &szDoc[nChar] ); if ( ! szDoc[nChar] ) return false; */ return true;}bool CMarkupSTL::x_FindToken( CMarkupSTL::TokenPos& token ){ // Starting at token.nNext, bypass whitespace and find the next token // returns true on success, members of token point to token // returns false on end of document, members point to end of document const char* szDoc = token.szDoc; int nChar = token.nNext; token.bIsString = false; // By-pass leading whitespace while ( szDoc[nChar] && strchr(" \t\n\r",szDoc[nChar]) ) ++nChar; if ( ! szDoc[nChar] ) { // No token was found before end of document token.nL = nChar; token.nR = nChar; token.nNext = nChar; return false; } // Is it an opening quote? char cFirstChar = szDoc[nChar]; if ( cFirstChar == '\"' || cFirstChar == '\'' ) { token.bIsString = true; // Move past opening quote ++nChar; token.nL = nChar; // Look for closing quote x_FindChar( token.szDoc, nChar, cFirstChar ); // 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 { // Go until special char or whitespace token.nL = nChar; while ( szDoc[nChar] && ! strchr(" \t\n\r<>=\\/?!",szDoc[nChar]) ) nChar += 1; // 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; return true;}string CMarkupSTL::x_GetToken( const CMarkupSTL::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.nL > token.nR ) return ""; return m_strDoc.substr( token.nL, token.nR - token.nL + ((token.nR<m_strDoc.size())? 1:0) );}int CMarkupSTL::x_FindElem( int iPosParent, int iPos, const char* szPath ){ // If szPath is NULL or empty, go to next sibling element // Otherwise go to next sibling element with matching path // if ( iPos ) iPos = m_aPos[iPos].iElemNext; else iPos = m_aPos[iPosParent].iElemChild; // Finished here if szPath not specified if ( szPath == NULL || !szPath[0] ) return iPos; // Search TokenPos token( m_strDoc.c_str() ); while ( iPos ) { // Compare tag name token.nNext = m_aPos[iPos].nStartL + 1; x_FindToken( token ); // Locate tag name if ( token.Match(szPath) ) return iPos; iPos = m_aPos[iPos].iElemNext; } return 0;}int CMarkupSTL::x_ParseNode( CMarkupSTL::TokenPos& token ){ // Call this with token.nNext set to the start of the node // This returns the node type and token.nNext set to the char after the node // If the node is not found or an element, token.nR is not determined // White space between elements is a text node int nTypeFound = 0; const char* szDoc = token.szDoc; token.nL = token.nNext; if ( szDoc[token.nL] == '<' ) { // Started with <, could be: // <!--...--> comment // <!DOCTYPE ...> dtd // <?target ...?> processing instruction // <![CDATA[...]]> cdata section // <NAME ...> element // if ( ! szDoc[token.nL+1] || ! szDoc[token.nL+2] ) return 0; char cFirstChar = szDoc[token.nL+1]; const char* szEndOfNode = NULL; if ( cFirstChar == '?' ) { nTypeFound = MNT_PROCESSING_INSTRUCTION; // processing instruction szEndOfNode = "?>"; } else if ( cFirstChar == '!' ) { char cSecondChar = szDoc[token.nL+2]; if ( cSecondChar == '[' ) { nTypeFound = MNT_CDATA_SECTION; szEndOfNode = "]]>"; } else if ( cSecondChar == '-' ) { nTypeFound = MNT_COMMENT; szEndOfNode = "-->"; } else { // Document type requires tokenizing because of strings and brackets nTypeFound = 0; int nBrackets = 0; while ( x_FindToken(token) ) { if ( ! token.bIsString ) { char cChar = szDoc[token.nL]; if ( cChar == '[' ) ++nBrackets; else if ( cChar == ']' ) --nBrackets; else if ( nBrackets == 0 && cChar == '>' ) { nTypeFound = MNT_DOCUMENT_TYPE; break; } } } if ( ! nTypeFound ) return 0; } } else if ( cFirstChar == '/' ) { // End tag means no node found within parent element return 0; } else { nTypeFound = MNT_ELEMENT; } // Search for end of node if not found yet if ( szEndOfNode ) { const char* pEnd = strstr( &szDoc[token.nNext], szEndOfNode ); if ( ! pEnd ) return 0; // not well-formed token.nNext = (pEnd - szDoc) + strlen(szEndOfNode); } } else if ( szDoc[token.nL] ) { // It is text or whitespace because it did not start with < nTypeFound = MNT_WHITESPACE; if ( x_FindToken(token) ) { if ( szDoc[token.nL] == '<' ) token.nNext = token.nL; else { nTypeFound = MNT_TEXT; x_FindChar( token.szDoc, token.nNext, '<' ); } } } return nTypeFound;}string CMarkupSTL::x_GetTagName( int iPos ) const{ // Return the tag name at specified element TokenPos token( m_strDoc.c_str() ); token.nNext = m_aPos[iPos].nStartL + 1; if ( ! iPos || ! x_FindToken( token ) ) return ""; // Return substring of document return x_GetToken( token );}bool CMarkupSTL::x_FindAttrib( CMarkupSTL::TokenPos& token, const char* 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_strDoc[token.nL] == '>' || m_strDoc[token.nL] == '/' ) break; // attrib not found // Equal sign if ( m_strDoc[token.nL] == '=' ) continue; // Potential attribute if ( ! nAttrib && nCount ) { // Attribute name search? if ( ! szAttrib || ! szAttrib[0] ) return true; // return with token at attrib name // Compare szAttrib if ( token.Match(szAttrib) ) nAttrib = nCount; } } else if ( nAttrib && nCount == nAttrib + 2 ) { return true; } } // Not found return false;}string CMarkupSTL::x_GetAttrib( int iPos, const char* szAttrib ) const{ // Return the value of the attrib at specified element if ( ! iPos || m_nNodeType != MNT_ELEMENT ) return ""; TokenPos token( m_strDoc.c_str() ); token.nNext = m_aPos[iPos].nStartL + 1; if ( szAttrib && x_FindAttrib( token, szAttrib ) ) return x_TextFromDoc( token.nL, token.nR - ((token.nR<m_strDoc.size())?0:1) ); return "";}bool CMarkupSTL::x_SetAttrib( int iPos, const char* szAttrib, int nValue ){ // Convert integer to string and call SetChildAttrib char szVal[25]; sprintf( szVal, "%d", nValue ); return x_SetAttrib( iPos, szAttrib, szVal );}bool CMarkupSTL::x_SetAttrib( int iPos, const char* szAttrib, const char* szValue ){ // Set attribute in iPos element if ( ! iPos || m_nNodeType != MNT_ELEMENT ) return false; TokenPos token( m_strDoc.c_str() ); token.nNext = m_aPos[iPos].nStartL + 1; int nInsertAt, nReplace = 0; string strInsert; if ( x_FindAttrib( token, szAttrib ) ) { // Decision: for empty value leaving attrib="" instead of removing attrib // Replace value only strInsert = x_TextToDoc( szValue, true ); nInsertAt = token.nL; nReplace = token.nR-token.nL+1; } else { // Insert string name value pair string strFormat; strFormat = " "; strFormat += szAttrib; strFormat += "=\""; strFormat += x_TextToDoc( szValue, true ); strFormat += "\""; strInsert = strFormat; // take into account whether it is an empty element nInsertAt = m_aPos[iPos].nStartR - (m_aPos[iPos].IsEmptyElement()?1:0); } x_DocChange( nInsertAt, nReplace, strInsert ); int nAdjust = strInsert.size() - nReplace; m_aPos[iPos].nStartR += nAdjust; m_aPos[iPos].AdjustEnd( nAdjust ); x_Adjust( iPos, nAdjust ); MARKUP_SETDEBUGSTATE; return true;}bool CMarkupSTL::x_CreateNode( string& strNode, int nNodeType, const char* szText ){ // Set strNode based on nNodeType and szText // Return false if szText would jeopardize well-formed document // switch ( nNodeType ) { case MNT_CDATA_SECTION: if ( strstr(szText,"]]>") != NULL ) return false; strNode = "<![CDATA["; strNode += szText; strNode += "]]>"; break; } return true;}bool CMarkupSTL::x_SetData( int iPos, const char* szData, int nCDATA ){ // Set data at specified position // if nCDATA==1, set content of element to a CDATA Section string strInsert; // Set data in iPos element if ( ! iPos || m_aPos[iPos].iElemChild ) return false; // Build strInsert from szData based on nCDATA // If CDATA section not valid, use parsed text (PCDATA) instead if ( nCDATA != 0 ) if ( ! x_CreateNode(strInsert, MNT_CDATA_SECTION, szData) ) nCDATA = 0; if ( nCDATA == 0 ) strInsert = x_TextToDoc( szData ); // Decide where to insert int nInsertAt, nReplace; if ( m_aPos[iPos].IsEmptyElement() ) { nInsertAt = m_aPos[iPos].nEndL; nReplace = 1; // Pre-adjust since <NAME/> becomes <NAME>data</NAME> string strTagName = x_GetTagName( iPos ); m_aPos[iPos].nStartR -= 1; m_aPos[iPos].nEndL -= (1 + strTagName.size()); string strFormat; strFormat = ">"; strFormat += strInsert; strFormat += "</"; strFormat += strTagName; strInsert = strFormat; } else { nInsertAt = m_aPos[iPos].nStartR+1; nReplace = m_aPos[iPos].nEndL - m_aPos[iPos].nStartR - 1; } x_DocChange( nInsertAt, nReplace, strInsert ); int nAdjust = strInsert.size() - nReplace; x_Adjust( iPos, nAdjust ); m_aPos[iPos].AdjustEnd( nAdjust ); MARKUP_SETDEBUGSTATE; return true;}string CMarkupSTL::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( m_strDoc.c_str() ); token.nNext = m_aPos[iPos].nStartR+1; if ( x_FindToken( token ) && m_strDoc[token.nL] == '<' && token.nL + 11 < m_aPos[iPos].nEndL && strncmp( &token.szDoc[token.nL+1], "![CDATA[", 8 ) == 0 ) { int nEndCDATA = m_strDoc.find( "]]>", token.nNext ); if ( nEndCDATA != string::npos && nEndCDATA < m_aPos[iPos].nEndL ) { return m_strDoc.substr( token.nL+9, nEndCDATA-token.nL-9 ); } } return x_TextFromDoc( m_aPos[iPos].nStartR+1, m_aPos[iPos].nEndL-1 ); } return "";}string CMarkupSTL::x_TextToDoc( const char* szText, bool bAttrib ) const{ // // < less than // & ampersand // > greater than // // and for attributes: // // ' apostrophe or single quote // " double quote // static char* szaReplace[] = { "<","&",">","'",""" }; const char* pFind = bAttrib?"<&>\'\"":"<&>"; const char* pSource = szText; string strResult; int nLen = strlen( szText ); strResult.reserve( nLen + nLen / 10 ); char cSource = *pSource; char* pFound; while ( cSource ) { if ( (pFound=strchr(pFind,cSource)) != NULL ) { pFound = szaReplace[pFound-pFind];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -