📄 cpl_minixml.cpp
字号:
CPLXMLNode *psReturn = NULL;
while( psTree != NULL )
{
CPLXMLNode *psCopy;
psCopy = CPLCreateXMLNode( NULL, psTree->eType, psTree->pszValue );
if( psReturn == NULL )
psReturn = psCopy;
if( psPrevious != NULL )
psPrevious->psNext = psCopy;
if( psTree->psChild != NULL )
psCopy->psChild = CPLCloneXMLTree( psTree->psChild );
psPrevious = psCopy;
psTree = psTree->psNext;
}
return psReturn;
}
/************************************************************************/
/* CPLSetXMLValue() */
/************************************************************************/
/**
* \brief Set element value by path.
*
* Find (or create) the target element or attribute specified in the
* path, and assign it the indicated value.
*
* Any path elements that do not already exist will be created. The target
* nodes value (the first CXT_Text child) will be replaced with the provided
* value.
*
* If the target node is an attribute instead of an element, the last separator
* should be a "#" instead of the normal period path separator.
*
* Example:
* CPLSetXMLValue( "Citation.Id.Description", "DOQ dataset" );
* CPLSetXMLValue( "Citation.Id.Description#name", "doq" );
*
* @param psRoot the subdocument to be updated.
*
* @param pszPath the dot seperated path to the target element/attribute.
*
* @param pszValue the text value to assign.
*
* @return TRUE on success.
*/
int CPLSetXMLValue( CPLXMLNode *psRoot, const char *pszPath,
const char *pszValue )
{
char **papszTokens;
int iToken = 0;
papszTokens = CSLTokenizeStringComplex( pszPath, ".", FALSE, FALSE );
while( papszTokens[iToken] != NULL && psRoot != NULL )
{
CPLXMLNode *psChild;
int bIsAttribute = FALSE;
const char *pszName = papszTokens[iToken];
if( pszName[0] == '#' )
{
bIsAttribute = TRUE;
pszName++;
}
if( psRoot->eType != CXT_Element )
return FALSE;
for( psChild = psRoot->psChild; psChild != NULL;
psChild = psChild->psNext )
{
if( psChild->eType != CXT_Text
&& EQUAL(pszName,psChild->pszValue) )
break;
}
if( psChild == NULL )
{
if( bIsAttribute )
psChild = CPLCreateXMLNode( psRoot, CXT_Attribute, pszName );
else
psChild = CPLCreateXMLNode( psRoot, CXT_Element, pszName );
}
psRoot = psChild;
iToken++;
}
CSLDestroy( papszTokens );
/* -------------------------------------------------------------------- */
/* Find the "text" child if there is one. */
/* -------------------------------------------------------------------- */
CPLXMLNode *psTextChild = psRoot->psChild;
while( psTextChild != NULL && psTextChild->eType != CXT_Text )
psTextChild = psTextChild->psNext;
/* -------------------------------------------------------------------- */
/* Now set a value node under this node. */
/* -------------------------------------------------------------------- */
if( psTextChild == NULL )
CPLCreateXMLNode( psRoot, CXT_Text, pszValue );
else
{
CPLFree( psTextChild->pszValue );
psTextChild->pszValue = CPLStrdup( pszValue );
}
return TRUE;
}
/************************************************************************/
/* CPLStripXMLNamespace() */
/************************************************************************/
/**
* \brief Strip indicated namespaces.
*
* The subdocument (psRoot) is recursively examined, and any elements
* with the indicated namespace prefix will have the namespace prefix
* stripped from the element names. If the passed namespace is NULL, then
* all namespace prefixes will be stripped.
*
* Nodes other than elements should remain unaffected. The changes are
* made "in place", and should not alter any node locations, only the
* pszValue field of affected nodes.
*
* @param psRoot the document to operate on.
* @param pszNamespace the name space prefix (not including colon), or NULL.
* @param bRecurse TRUE to recurse over whole document, or FALSE to only
* operate on the passed node.
*/
void CPLStripXMLNamespace( CPLXMLNode *psRoot,
const char *pszNamespace,
int bRecurse )
{
if( psRoot == NULL )
return;
if( psRoot->eType == CXT_Element || psRoot->eType == CXT_Attribute )
{
if( pszNamespace != NULL )
{
if( EQUALN(pszNamespace,psRoot->pszValue,strlen(pszNamespace))
&& psRoot->pszValue[strlen(pszNamespace)] == ':' )
{
char *pszNewValue =
CPLStrdup(psRoot->pszValue+strlen(pszNamespace)+1);
CPLFree( psRoot->pszValue );
psRoot->pszValue = pszNewValue;
}
}
else
{
const char *pszCheck;
for( pszCheck = psRoot->pszValue; *pszCheck != '\0'; pszCheck++ )
{
if( *pszCheck == ':' )
{
char *pszNewValue = CPLStrdup( pszCheck+1 );
CPLFree( psRoot->pszValue );
psRoot->pszValue = pszNewValue;
break;
}
}
}
}
if( bRecurse )
{
if( psRoot->psChild != NULL )
CPLStripXMLNamespace( psRoot->psChild, pszNamespace, 1 );
if( psRoot->psNext != NULL )
CPLStripXMLNamespace( psRoot->psNext, pszNamespace, 1 );
}
}
/************************************************************************/
/* CPLParseXMLFile() */
/************************************************************************/
/**
* \brief Parse XML file into tree.
*
* The named file is opened, loaded into memory as a big string, and
* parsed with CPLParseXMLString(). Errors in reading the file or parsing
* the XML will be reported by CPLError().
*
* The "large file" API is used, so XML files can come from virtualized
* files.
*
* @param pszFilename the file to open.
*
* @return NULL on failure, or the document tree on success.
*/
CPLXMLNode *CPLParseXMLFile( const char *pszFilename )
{
FILE *fp;
vsi_l_offset nLen;
char *pszDoc;
CPLXMLNode *psTree;
/* -------------------------------------------------------------------- */
/* Read the file. */
/* -------------------------------------------------------------------- */
fp = VSIFOpenL( pszFilename, "rb" );
if( fp == NULL )
{
CPLError( CE_Failure, CPLE_OpenFailed,
"Failed to open %.500s to read.", pszFilename );
return NULL;
}
VSIFSeekL( fp, 0, SEEK_END );
nLen = VSIFTellL( fp );
VSIFSeekL( fp, 0, SEEK_SET );
pszDoc = (char *) VSIMalloc((size_t)nLen + 1);
if( pszDoc == NULL )
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"Out of memory allocating space for %d byte buffer in\n"
"CPLParseXMLFile(%.500s).",
nLen+1, pszFilename );
VSIFCloseL( fp );
return NULL;
}
if( VSIFReadL( pszDoc, 1, (size_t)nLen, fp ) < nLen )
{
CPLError( CE_Failure, CPLE_FileIO,
"VSIFRead() result short of expected %d bytes from %.500s.",
nLen, pszFilename );
pszDoc[0] = '\0';
}
VSIFCloseL( fp );
pszDoc[nLen] = '\0';
/* -------------------------------------------------------------------- */
/* Parse it. */
/* -------------------------------------------------------------------- */
psTree = CPLParseXMLString( pszDoc );
CPLFree( pszDoc );
return psTree;
}
/************************************************************************/
/* CPLSerializeXMLTreeToFile() */
/************************************************************************/
/**
* \brief Write document tree to a file.
*
* The passed document tree is converted into one big string (with
* CPLSerializeXMLTree()) and then written to the named file. Errors writing
* the file will be reported by CPLError(). The source document tree is
* not altered. If the output file already exists it will be overwritten.
*
* @param psTree the document tree to write.
* @param pszFilename the name of the file to write to.
* @return TRUE on success, FALSE otherwise.
*/
int CPLSerializeXMLTreeToFile( CPLXMLNode *psTree, const char *pszFilename )
{
char *pszDoc;
FILE *fp;
vsi_l_offset nLength;
/* -------------------------------------------------------------------- */
/* Serialize document. */
/* -------------------------------------------------------------------- */
pszDoc = CPLSerializeXMLTree( psTree );
if( pszDoc == NULL )
return FALSE;
nLength = strlen(pszDoc);
/* -------------------------------------------------------------------- */
/* Create file. */
/* -------------------------------------------------------------------- */
fp = VSIFOpenL( pszFilename, "wt" );
if( fp == NULL )
{
CPLError( CE_Failure, CPLE_OpenFailed,
"Failed to open %.500s to write.", pszFilename );
return FALSE;
}
/* -------------------------------------------------------------------- */
/* Write file. */
/* -------------------------------------------------------------------- */
if( VSIFWriteL( pszDoc, 1, nLength, fp ) != nLength )
{
CPLError( CE_Failure, CPLE_FileIO,
"Failed to write whole XML document (%.500s).",
pszFilename );
VSIFCloseL( fp );
CPLFree( pszDoc );
return FALSE;
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
VSIFCloseL( fp );
CPLFree( pszDoc );
return TRUE;
}
/************************************************************************/
/* CPLCleanXMLElementName() */
/************************************************************************/
/**
* \brief Make string into safe XML token.
*
* Modififies a string in place to try and make it into a legal
* XML token that can be used as an element name. This is accomplished
* by changing any characters not legal in a token into an underscore.
*
* NOTE: This function should implement the rules in section 2.3 of
* http://www.w3.org/TR/xml11/ but it doesn't yet do that properly. We
* only do a rough approximation of that.
*
* @param pszTarget the string to be adjusted. It is altered in place.
*/
void CPLCleanXMLElementName( char *pszTarget )
{
if( pszTarget == NULL )
return;
for( ; *pszTarget != '\0'; pszTarget++ )
{
if( (*((unsigned char *) pszTarget) & 0x80) || isalnum( *pszTarget )
|| *pszTarget == '_' || *pszTarget == '.' )
{
/* ok */
}
else
{
*pszTarget = '_';
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -