📄 cpl_minixml.cpp
字号:
* * @return a copy of the whole tree. */CPLXMLNode *CPLCloneXMLTree( CPLXMLNode *psTree ){ CPLXMLNode *psPrevious = NULL; 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. */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 + -