📄 cpl_minixml.cpp
字号:
}
/* -------------------------------------------------------------------- */
/* Search siblings if we are in side search mode. */
/* -------------------------------------------------------------------- */
if( bSideSearch )
{
for( psRoot = psRoot->psNext; psRoot != NULL; psRoot = psRoot->psNext )
{
psResult = CPLSearchXMLNode( psRoot, pszElement );
if( psResult != NULL )
return psResult;
}
}
return NULL;
}
/************************************************************************/
/* CPLGetXMLNode() */
/************************************************************************/
/**
* \brief Find node by path.
*
* Searches the document or subdocument indicated by psRoot for an element
* (or attribute) with the given path. The path should consist of a set of
* element names separated by dots, not including the name of the root
* element (psRoot). If the requested element is not found NULL is returned.
*
* Attribute names may only appear as the last item in the path.
*
* The search is done from the root nodes children, but all intermediate
* nodes in the path must be specified. Seaching for "name" would only find
* a name element or attribute if it is a direct child of the root, not at any
* level in the subdocument.
*
* If the pszPath is prefixed by "=" then the search will begin with the
* root node, and it's siblings, instead of the root nodes children. This
* is particularly useful when searching within a whole document which is
* often prefixed by one or more "junk" nodes like the <?xml> declaration.
*
* @param psRoot the subtree in which to search. This should be a node of
* type CXT_Element. NULL is safe.
*
* @param pszPath the list of element names in the path (dot separated).
*
* @return the requested element node, or NULL if not found.
*/
CPLXMLNode *CPLGetXMLNode( CPLXMLNode *psRoot, const char *pszPath )
{
char **papszTokens;
int iToken = 0;
int bSideSearch = FALSE;
if( psRoot == NULL )
return NULL;
if( *pszPath == '=' )
{
bSideSearch = TRUE;
pszPath++;
}
papszTokens = CSLTokenizeStringComplex( pszPath, ".", FALSE, FALSE );
while( papszTokens[iToken] != NULL && psRoot != NULL )
{
CPLXMLNode *psChild;
if( bSideSearch )
{
psChild = psRoot;
bSideSearch = FALSE;
}
else
psChild = psRoot->psChild;
for( ; psChild != NULL; psChild = psChild->psNext )
{
if( psChild->eType != CXT_Text
&& EQUAL(papszTokens[iToken],psChild->pszValue) )
break;
}
if( psChild == NULL )
{
psRoot = NULL;
break;
}
psRoot = psChild;
iToken++;
}
CSLDestroy( papszTokens );
return psRoot;
}
/************************************************************************/
/* CPLGetXMLValue() */
/************************************************************************/
/**
* \brief Fetch element/attribute value.
*
* Searches the document for the element/attribute value associated with
* the path. The corresponding node is internally found with CPLGetXMLNode()
* (see there for details on path handling). Once found, the value is
* considered to be the first CXT_Text child of the node.
*
* If the attribute/element search fails, or if the found node has not
* value then the passed default value is returned.
*
* The returned value points to memory within the document tree, and should
* not be altered or freed.
*
* @param psRoot the subtree in which to search. This should be a node of
* type CXT_Element. NULL is safe.
*
* @param pszPath the list of element names in the path (dot separated). An
* empty path means get the value of the psRoot node.
*
* @param pszDefault the value to return if a corresponding value is not
* found, may be NULL.
*
* @return the requested value or pszDefault if not found.
*/
const char *CPLGetXMLValue( CPLXMLNode *psRoot, const char *pszPath,
const char *pszDefault )
{
CPLXMLNode *psTarget;
if( pszPath == NULL || *pszPath == '\0' )
psTarget = psRoot;
else
psTarget = CPLGetXMLNode( psRoot, pszPath );
if( psTarget == NULL )
return pszDefault;
if( psTarget->eType == CXT_Attribute )
{
CPLAssert( psTarget->psChild != NULL
&& psTarget->psChild->eType == CXT_Text );
return psTarget->psChild->pszValue;
}
if( psTarget->eType == CXT_Element )
{
// Find first non-attribute child, and verify it is a single text
// with no siblings
psTarget = psTarget->psChild;
while( psTarget != NULL && psTarget->eType == CXT_Attribute )
psTarget = psTarget->psNext;
if( psTarget != NULL
&& psTarget->eType == CXT_Text
&& psTarget->psNext == NULL )
return psTarget->pszValue;
}
return pszDefault;
}
/************************************************************************/
/* CPLAddXMLChild() */
/************************************************************************/
/**
* \brief Add child node to parent.
*
* The passed child is added to the list of children of the indicated
* parent. Normally the child is added at the end of the parents child
* list, but attributes (CXT_Attribute) will be inserted after any other
* attributes but before any other element type. Ownership of the child
* node is effectively assumed by the parent node. If the child has
* siblings (it's psNext is not NULL) they will be trimmed, but if the child
* has children they are carried with it.
*
* @param psParent the node to attach the child to. May not be NULL.
*
* @param psChild the child to add to the parent. May not be NULL. Should
* not be a child of any other parent.
*/
void CPLAddXMLChild( CPLXMLNode *psParent, CPLXMLNode *psChild )
{
CPLXMLNode *psSib;
if( psParent->psChild == NULL )
{
psParent->psChild = psChild;
return;
}
// Insert at head of list if first child is not attribute.
if( psChild->eType == CXT_Attribute
&& psParent->psChild->eType != CXT_Attribute )
{
psChild->psNext = psParent->psChild;
psParent->psChild = psChild;
return;
}
// Search for end of list.
for( psSib = psParent->psChild;
psSib->psNext != NULL;
psSib = psSib->psNext )
{
// Insert attributes if the next node is not an attribute.
if( psChild->eType == CXT_Attribute
&& psSib->psNext != NULL
&& psSib->psNext->eType != CXT_Attribute )
{
psChild->psNext = psSib->psNext;
psSib->psNext = psChild;
return;
}
}
psSib->psNext = psChild;
}
/************************************************************************/
/* CPLAddXMLChild() */
/************************************************************************/
/**
* \brief Remove child node from parent.
*
* The passed child is removed from the child list of the passed parent,
* but the child is not destroyed. The child retains ownership of it's
* own children, but is cleanly removed from the child list of the parent.
*
* @param psParent the node to the child is attached to.
*
* @param psChild the child to remove.
*
* @return TRUE on success or FALSE if the child was not found.
*/
int CPLRemoveXMLChild( CPLXMLNode *psParent, CPLXMLNode *psChild )
{
CPLXMLNode *psLast = NULL, *psThis;
if( psParent == NULL )
return FALSE;
for( psThis = psParent->psChild;
psThis != NULL;
psLast = psThis, psThis = psThis->psNext )
{
if( psThis == psChild )
{
if( psLast == NULL )
psParent->psChild = psThis->psNext;
else
psLast->psNext = psThis->psNext;
psThis->psNext = NULL;
return TRUE;
}
}
return FALSE;
}
/************************************************************************/
/* CPLAddXMLSibling() */
/************************************************************************/
/**
* \brief Add new sibling.
*
* The passed psNewSibling is added to the end of siblings of the
* psOlderSibling node. That is, it is added to the end of the psNext
* chain. There is no special handling if psNewSibling is an attribute.
* If this is required, use CPLAddXMLChild().
*
* @param psOlderSibling the node to attach the sibling after.
*
* @param psNewSibling the node to add at the end of psOlderSiblings psNext
* chain.
*/
void CPLAddXMLSibling( CPLXMLNode *psOlderSibling, CPLXMLNode *psNewSibling )
{
if( psOlderSibling == NULL )
return;
while( psOlderSibling->psNext != NULL )
psOlderSibling = psOlderSibling->psNext;
psOlderSibling->psNext = psNewSibling;
}
/************************************************************************/
/* CPLCreateXMLElementAndValue() */
/************************************************************************/
/**
* \brief Create an element and text value.
*
* This is function is a convenient short form for:
*
* \code
* CPLXMLNode *psTextNode;
* CPLXMLNode *psElementNode;
*
* psElementNode = CPLCreateXMLNode( psParent, CXT_Element, pszName );
* psTextNode = CPLCreateXMLNode( psElementNode, CXT_Text, pszValue );
*
* return psElementNode;
* \endcode
*
* It creates a CXT_Element node, with a CXT_Text child, and
* attaches the element to the passed parent.
*
* @param psParent the parent node to which the resulting node should
* be attached. May be NULL to keep as freestanding.
*
* @param pszName the element name to create.
* @param pszValue the text to attach to the element. Must not be NULL.
*
* @return the pointer to the new element node.
*/
CPLXMLNode *CPLCreateXMLElementAndValue( CPLXMLNode *psParent,
const char *pszName,
const char *pszValue )
{
CPLXMLNode *psTextNode;
CPLXMLNode *psElementNode;
psElementNode = CPLCreateXMLNode( psParent, CXT_Element, pszName );
psTextNode = CPLCreateXMLNode( psElementNode, CXT_Text, pszValue );
return psElementNode;
}
/************************************************************************/
/* CPLCloneXMLTree() */
/************************************************************************/
/**
* \brief Copy tree.
*
* Creates a deep copy of a CPLXMLNode tree.
*
* @param psTree the tree to duplicate.
*
* @return a copy of the whole tree.
*/
CPLXMLNode *CPLCloneXMLTree( CPLXMLNode *psTree )
{
CPLXMLNode *psPrevious = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -