📄 cpl_minixml.cpp
字号:
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 );
}
/* -------------------------------------------------------------------- */
/* Anything else is an error. */
/* -------------------------------------------------------------------- */
else
{
CPLError( CE_Failure, CPLE_AppDefined,
"Parse error at line %d, unexpected token:%.500s\n",
sContext.nInputLine, sContext.pszToken );
break;
}
}
/* -------------------------------------------------------------------- */
/* Did we pop all the way out of our stack? */
/* -------------------------------------------------------------------- */
if( CPLGetLastErrorType() == CE_None && sContext.nStackSize != 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Parse error at EOF, not all elements have been closed,\n"
"starting with %.500s\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -