📄 cpl_minixml.cpp
字号:
else if( psContext->bInElement && chNext == '\'' ) { psContext->eTokenType = TString; while( (chNext = ReadChar(psContext)) != '\'' && chNext != '\0' ) AddToToken( psContext, chNext ); if( chNext != '\'' ) { psContext->eTokenType = TNone; CPLError( CE_Failure, CPLE_AppDefined, "Parse error on line %d, reached EOF before closing quote.", psContext->nInputLine ); } /* Do we need to unescape it? */ if( strchr(psContext->pszToken,'&') != NULL ) { int nLength; char *pszUnescaped = CPLUnescapeString( psContext->pszToken, &nLength, CPLES_XML ); strcpy( psContext->pszToken, pszUnescaped ); CPLFree( pszUnescaped ); psContext->nTokenSize = strlen(psContext->pszToken ); } }/* -------------------------------------------------------------------- *//* Collect an unquoted string, terminated by a open angle *//* bracket. *//* -------------------------------------------------------------------- */ else if( !psContext->bInElement ) { psContext->eTokenType = TString; AddToToken( psContext, chNext ); while( (chNext = ReadChar(psContext)) != '<' && chNext != '\0' ) AddToToken( psContext, chNext ); UnreadChar( psContext, chNext ); /* Do we need to unescape it? */ if( strchr(psContext->pszToken,'&') != NULL ) { int nLength; char *pszUnescaped = CPLUnescapeString( psContext->pszToken, &nLength, CPLES_XML ); strcpy( psContext->pszToken, pszUnescaped ); CPLFree( pszUnescaped ); psContext->nTokenSize = strlen(psContext->pszToken ); } } /* -------------------------------------------------------------------- *//* Collect a regular token terminated by white space, or *//* special character(s) like an equal sign. *//* -------------------------------------------------------------------- */ else { psContext->eTokenType = TToken; /* add the first character to the token regardless of what it is */ AddToToken( psContext, chNext ); for( chNext = ReadChar(psContext); (chNext >= 'A' && chNext <= 'Z') || (chNext >= 'a' && chNext <= 'z') || chNext == '-' || chNext == '_' || chNext == '.' || chNext == ':' || (chNext >= '0' && chNext <= '9'); chNext = ReadChar(psContext) ) { AddToToken( psContext, chNext ); } UnreadChar(psContext, chNext); } return psContext->eTokenType;} /************************************************************************//* PushNode() *//************************************************************************/static void PushNode( ParseContext *psContext, CPLXMLNode *psNode ){ if( psContext->nStackMaxSize <= psContext->nStackSize ) { psContext->nStackMaxSize += 10; psContext->papsStack = (CPLXMLNode **) CPLRealloc(psContext->papsStack, sizeof(CPLXMLNode*) * psContext->nStackMaxSize); } psContext->papsStack[psContext->nStackSize++] = psNode;} /************************************************************************//* AttachNode() *//* *//* Attach the passed node as a child of the current node. *//* Special handling exists for adding siblings to psFirst if *//* there is nothing on the stack. *//************************************************************************/static void AttachNode( ParseContext *psContext, CPLXMLNode *psNode ){ if( psContext->psFirstNode == NULL ) psContext->psFirstNode = psNode; else if( psContext->nStackSize == 0 ) { CPLXMLNode *psSibling; psSibling = psContext->psFirstNode; while( psSibling->psNext != NULL ) psSibling = psSibling->psNext; psSibling->psNext = psNode; } else if( psContext->papsStack[psContext->nStackSize-1]->psChild == NULL ) { psContext->papsStack[psContext->nStackSize-1]->psChild = psNode; } else { CPLXMLNode *psSibling; psSibling = psContext->papsStack[psContext->nStackSize-1]->psChild; while( psSibling->psNext != NULL ) psSibling = psSibling->psNext; psSibling->psNext = psNode; }}/************************************************************************//* CPLParseXMLString() *//************************************************************************//** * \brief Parse an XML string into tree form. * * The passed document is parsed into a CPLXMLNode tree representation. * If the document is not well formed XML then NULL is returned, and errors * are reported via CPLError(). No validation beyond wellformedness is * done. The CPLParseXMLFile() convenience function can be used to parse * from a file. * * The returned document tree is is owned by the caller and should be freed * with CPLDestroyXMLNode() when no longer needed. * * If the document has more than one "root level" element then those after the * first will be attached to the first as siblings (via the psNext pointers) * even though there is no common parent. A document with no XML structure * (no angle brackets for instance) would be considered well formed, and * returned as a single CXT_Text node. * * @param pszString the document to parse. * * @return parsed tree or NULL on error. */CPLXMLNode *CPLParseXMLString( const char *pszString ){ ParseContext sContext; CPLErrorReset(); if( pszString == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "CPLParseXMLString() called with NULL pointer." ); return NULL; }/* -------------------------------------------------------------------- *//* Initialize parse context. *//* -------------------------------------------------------------------- */ sContext.pszInput = pszString; sContext.nInputOffset = 0; sContext.nInputLine = 0; sContext.bInElement = FALSE; sContext.pszToken = NULL; sContext.nTokenMaxSize = 0; sContext.nTokenSize = 0; sContext.eTokenType = TNone; sContext.nStackMaxSize = 0; sContext.nStackSize = 0; sContext.papsStack = NULL; sContext.psFirstNode = NULL; /* ensure token is initialized */ AddToToken( &sContext, ' ' ); /* ==================================================================== *//* Loop reading tokens. *//* ==================================================================== */ while( ReadToken( &sContext ) != TNone ) {/* -------------------------------------------------------------------- *//* Create a new element. *//* -------------------------------------------------------------------- */ if( sContext.eTokenType == TOpen ) { CPLXMLNode *psElement; if( ReadToken(&sContext) != TToken ) { CPLError( CE_Failure, CPLE_AppDefined, "Line %d: Didn't find element token after open angle bracket.", sContext.nInputLine ); break; } if( sContext.pszToken[0] != '/' ) { psElement = CPLCreateXMLNode( NULL, CXT_Element, sContext.pszToken ); AttachNode( &sContext, psElement ); PushNode( &sContext, psElement ); } else { if( sContext.nStackSize == 0 || !EQUAL(sContext.pszToken+1, sContext.papsStack[sContext.nStackSize-1]->pszValue) ) { CPLError( CE_Failure, CPLE_AppDefined, "Line %d: <%.500s> doesn't have matching <%.500s>.", sContext.nInputLine, sContext.pszToken, sContext.pszToken+1 ); break; } else { if( ReadToken(&sContext) != TClose ) { CPLError( CE_Failure, CPLE_AppDefined, "Line %d: Missing close angle bracket after <%.500s.", sContext.nInputLine, sContext.pszToken ); break; } /* pop element off stack */ sContext.nStackSize--; } } }/* -------------------------------------------------------------------- *//* Add an attribute to a token. *//* -------------------------------------------------------------------- */ else if( sContext.eTokenType == TToken ) { CPLXMLNode *psAttr; psAttr = CPLCreateXMLNode(NULL, CXT_Attribute, sContext.pszToken); AttachNode( &sContext, psAttr ); if( ReadToken(&sContext) != TEqual ) { CPLError( CE_Failure, CPLE_AppDefined, "Line %d: Didn't find expected '=' for value of attribute '%.500s'.", sContext.nInputLine, psAttr->pszValue ); break; } if( ReadToken(&sContext) != TString && sContext.eTokenType != TToken ) { CPLError( CE_Failure, CPLE_AppDefined, "Line %d: Didn't find expected attribute value.", sContext.nInputLine ); break; } CPLCreateXMLNode( psAttr, CXT_Text, sContext.pszToken ); }/* -------------------------------------------------------------------- *//* Close the start section of an element. *//* -------------------------------------------------------------------- */ else if( sContext.eTokenType == TClose ) { if( sContext.nStackSize == 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "Line %d: Found unbalanced '>'.", sContext.nInputLine ); break; } }/* -------------------------------------------------------------------- *//* Close the start section of an element, and pop it *//* immediately. *//* -------------------------------------------------------------------- */ else if( sContext.eTokenType == TSlashClose ) { if( sContext.nStackSize == 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "Line %d: Found unbalanced '/>'.", sContext.nInputLine ); break; } sContext.nStackSize--; }/* -------------------------------------------------------------------- *//* Close the start section of a <?...?> element, and pop it *//* immediately. *//* -------------------------------------------------------------------- */ else if( sContext.eTokenType == TQuestionClose ) { if( sContext.nStackSize == 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "Line %d: Found unbalanced '?>'.", sContext.nInputLine ); break; } else if( sContext.papsStack[sContext.nStackSize-1]->pszValue[0] != '?' ) { CPLError( CE_Failure, CPLE_AppDefined, "Line %d: Found '?>' without matching '<?'.", sContext.nInputLine ); break; } sContext.nStackSize--; }/* -------------------------------------------------------------------- *//* Handle comments. They are returned as a whole token with the *//* prefix and postfix omitted. No processing of white space *//* will be done. *//* -------------------------------------------------------------------- */ else if( sContext.eTokenType == TComment ) { CPLXMLNode *psValue; psValue = CPLCreateXMLNode(NULL, CXT_Comment, sContext.pszToken); AttachNode( &sContext, psValue ); }/* -------------------------------------------------------------------- *//* Handle literals. They are returned without processing. *//* -------------------------------------------------------------------- */ else if( sContext.eTokenType == TLiteral ) { CPLXMLNode *psValue; psValue = CPLCreateXMLNode(NULL, CXT_Literal, sContext.pszToken); AttachNode( &sContext, psValue ); }/* -------------------------------------------------------------------- *//* Add a text value node as a child of the current element. *//* -------------------------------------------------------------------- */ else if( sContext.eTokenType == TString && !sContext.bInElement ) { CPLXMLNode *psValue; psValue = CPLCreateXMLNode(NULL, CXT_Text, sContext.pszToken); AttachNode( &sContext, psValue ); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -