📄 cpl_minixml.cpp
字号:
sContext.papsStack[sContext.nStackSize-1]->pszValue );
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
CPLFree( sContext.pszToken );
if( sContext.papsStack != NULL )
CPLFree( sContext.papsStack );
if( CPLGetLastErrorType() != CE_None )
{
CPLDestroyXMLNode( sContext.psFirstNode );
sContext.psFirstNode = NULL;
}
return sContext.psFirstNode;
}
/************************************************************************/
/* _GrowBuffer() */
/************************************************************************/
static void _GrowBuffer( size_t nNeeded,
char **ppszText, unsigned int *pnMaxLength )
{
if( nNeeded+1 >= *pnMaxLength )
{
*pnMaxLength = MAX(*pnMaxLength * 2,nNeeded+1);
*ppszText = (char *) CPLRealloc(*ppszText, *pnMaxLength);
}
}
/************************************************************************/
/* CPLSerializeXMLNode() */
/************************************************************************/
static void
CPLSerializeXMLNode( CPLXMLNode *psNode, int nIndent,
char **ppszText, unsigned int *pnLength,
unsigned int *pnMaxLength )
{
if( psNode == NULL )
return;
/* -------------------------------------------------------------------- */
/* Ensure the buffer is plenty large to hold this additional */
/* string. */
/* -------------------------------------------------------------------- */
*pnLength += strlen(*ppszText + *pnLength);
_GrowBuffer( strlen(psNode->pszValue) + *pnLength + 40 + nIndent,
ppszText, pnMaxLength );
/* -------------------------------------------------------------------- */
/* Text is just directly emitted. */
/* -------------------------------------------------------------------- */
if( psNode->eType == CXT_Text )
{
char *pszEscaped = CPLEscapeString( psNode->pszValue, -1, CPLES_XML );
CPLAssert( psNode->psChild == NULL );
/* Escaped text might be bigger than expected. */
_GrowBuffer( strlen(pszEscaped) + *pnLength,
ppszText, pnMaxLength );
strcat( *ppszText + *pnLength, pszEscaped );
CPLFree( pszEscaped );
}
/* -------------------------------------------------------------------- */
/* Attributes require a little formatting. */
/* -------------------------------------------------------------------- */
else if( psNode->eType == CXT_Attribute )
{
CPLAssert( psNode->psChild != NULL
&& psNode->psChild->eType == CXT_Text );
sprintf( *ppszText + *pnLength, " %s=\"", psNode->pszValue );
CPLSerializeXMLNode( psNode->psChild, 0, ppszText,
pnLength, pnMaxLength );
strcat( *ppszText + *pnLength, "\"" );
}
/* -------------------------------------------------------------------- */
/* Handle comment output. */
/* -------------------------------------------------------------------- */
else if( psNode->eType == CXT_Comment )
{
int i;
CPLAssert( psNode->psChild == NULL );
for( i = 0; i < nIndent; i++ )
(*ppszText)[(*pnLength)++] = ' ';
sprintf( *ppszText + *pnLength, "<!--%s-->\n",
psNode->pszValue );
}
/* -------------------------------------------------------------------- */
/* Handle literal output (like <!DOCTYPE...>) */
/* -------------------------------------------------------------------- */
else if( psNode->eType == CXT_Literal )
{
int i;
CPLAssert( psNode->psChild == NULL );
for( i = 0; i < nIndent; i++ )
(*ppszText)[(*pnLength)++] = ' ';
strcpy( *ppszText + *pnLength, psNode->pszValue );
strcat( *ppszText + *pnLength, "\n" );
}
/* -------------------------------------------------------------------- */
/* Elements actually have to deal with general children, and */
/* various formatting issues. */
/* -------------------------------------------------------------------- */
else if( psNode->eType == CXT_Element )
{
int bHasNonAttributeChildren = FALSE;
CPLXMLNode *psChild;
memset( *ppszText + *pnLength, ' ', nIndent );
*pnLength += nIndent;
(*ppszText)[*pnLength] = '\0';
sprintf( *ppszText + *pnLength, "<%s", psNode->pszValue );
/* Serialize *all* the attribute children, regardless of order */
for( psChild = psNode->psChild;
psChild != NULL;
psChild = psChild->psNext )
{
if( psChild->eType == CXT_Attribute )
CPLSerializeXMLNode( psChild, 0, ppszText, pnLength,
pnMaxLength );
else
bHasNonAttributeChildren = TRUE;
}
if( !bHasNonAttributeChildren )
{
if( psNode->pszValue[0] == '?' )
strcat( *ppszText + *pnLength, "?>\n" );
else
strcat( *ppszText + *pnLength, "/>\n" );
}
else
{
int bJustText = TRUE;
strcat( *ppszText + *pnLength, ">" );
for( psChild = psNode->psChild;
psChild != NULL;
psChild = psChild->psNext )
{
if( psChild->eType == CXT_Attribute )
continue;
if( psChild->eType != CXT_Text && bJustText )
{
bJustText = FALSE;
strcat( *ppszText + *pnLength, "\n" );
}
CPLSerializeXMLNode( psChild, nIndent + 2, ppszText, pnLength,
pnMaxLength );
}
*pnLength += strlen(*ppszText + *pnLength);
_GrowBuffer( strlen(psNode->pszValue) + *pnLength + 40 + nIndent,
ppszText, pnMaxLength );
if( !bJustText )
{
memset( *ppszText + *pnLength, ' ', nIndent );
*pnLength += nIndent;
(*ppszText)[*pnLength] = '\0';
}
*pnLength += strlen(*ppszText + *pnLength);
sprintf( *ppszText + *pnLength, "</%s>\n", psNode->pszValue );
}
}
}
/************************************************************************/
/* CPLSerializeXMLTree() */
/************************************************************************/
/**
* \brief Convert tree into string document.
*
* This function converts a CPLXMLNode tree representation of a document
* into a flat string representation. White space indentation is used
* visually preserve the tree structure of the document. The returned
* document becomes owned by the caller and should be freed with CPLFree()
* when no longer needed.
*
* @param psNode
*
* @return the document on success or NULL on failure.
*/
char *CPLSerializeXMLTree( CPLXMLNode *psNode )
{
unsigned int nMaxLength = 100, nLength = 0;
char *pszText = NULL;
CPLXMLNode *psThis;
pszText = (char *) CPLMalloc(nMaxLength);
pszText[0] = '\0';
for( psThis = psNode; psThis != NULL; psThis = psThis->psNext )
CPLSerializeXMLNode( psThis, 0, &pszText, &nLength, &nMaxLength );
return pszText;
}
/************************************************************************/
/* CPLCreateXMLNode() */
/************************************************************************/
/**
* \brief Create an document tree item.
*
* Create a single CPLXMLNode object with the desired value and type, and
* attach it as a child of the indicated parent.
*
* @param poParent the parent to which this node should be attached as a
* child. May be NULL to keep as free standing.
*
* @return the newly created node, now owned by the caller (or parent node).
*/
CPLXMLNode *CPLCreateXMLNode( CPLXMLNode *poParent, CPLXMLNodeType eType,
const char *pszText )
{
CPLXMLNode *psNode;
/* -------------------------------------------------------------------- */
/* Create new node. */
/* -------------------------------------------------------------------- */
psNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
psNode->eType = eType;
psNode->pszValue = CPLStrdup( pszText );
/* -------------------------------------------------------------------- */
/* Attach to parent, if provided. */
/* -------------------------------------------------------------------- */
if( poParent != NULL )
{
if( poParent->psChild == NULL )
poParent->psChild = psNode;
else
{
CPLXMLNode *psLink = poParent->psChild;
while( psLink->psNext != NULL )
psLink = psLink->psNext;
psLink->psNext = psNode;
}
}
return psNode;
}
/************************************************************************/
/* CPLDestroyXMLNode() */
/************************************************************************/
/**
* \brief Destroy a tree.
*
* This function frees resources associated with a CPLXMLNode and all its
* children nodes.
*
* @param psNode the tree to free.
*/
void CPLDestroyXMLNode( CPLXMLNode *psNode )
{
if( psNode == NULL )
return;
if( psNode->psChild != NULL )
CPLDestroyXMLNode( psNode->psChild );
if( psNode->psNext != NULL )
CPLDestroyXMLNode( psNode->psNext );
CPLFree( psNode->pszValue );
CPLFree( psNode );
}
/************************************************************************/
/* CPLSearchXMLNode() */
/************************************************************************/
/**
* \brief Search for a node in document.
*
* Searches the children (and potentially siblings) of the documented
* passed in for the named element or attribute. To search following
* siblings as well as children, prefix the pszElement name with an equal
* sign. This function does an in-order traversal of the document tree.
* So it will first match against the current node, then it's first child,
* that childs first child, and so on.
*
* Use CPLGetXMLNode() to find a specific child, or along a specific
* node path.
*
* @param psRoot the subtree to search. This should be a node of type
* CXT_Element. NULL is safe.
*
* @param pszElement the name of the element or attribute to search for.
*
* @return The matching node or NULL on failure.
*/
CPLXMLNode *CPLSearchXMLNode( CPLXMLNode *psRoot, const char *pszElement )
{
int bSideSearch = FALSE;
CPLXMLNode *psChild, *psResult;
if( psRoot == NULL || pszElement == NULL )
return NULL;
if( *pszElement == '=' )
{
bSideSearch = TRUE;
pszElement++;
}
/* -------------------------------------------------------------------- */
/* Does this node match? */
/* -------------------------------------------------------------------- */
if( (psRoot->eType == CXT_Element
|| psRoot->eType == CXT_Attribute)
&& EQUAL(pszElement,psRoot->pszValue) )
return psRoot;
/* -------------------------------------------------------------------- */
/* Search children. */
/* -------------------------------------------------------------------- */
for( psChild = psRoot->psChild; psChild != NULL; psChild = psChild->psNext)
{
if( (psChild->eType == CXT_Element
|| psChild->eType == CXT_Attribute)
&& EQUAL(pszElement,psChild->pszValue) )
return psChild;
if( psChild->psChild != NULL )
{
psResult = CPLSearchXMLNode( psChild, pszElement );
if( psResult != NULL )
return psResult;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -