/** * \brief Import coordinate system from XML format (GML only currently). * * This method is the same as the C function OSRImportFromXML() * @param pszXML XML string to import * @return OGRERR_NONE on success or OGRERR_CORRUPT_DATA on failure. */ OGRErr OGRSpatialReference::importFromXML(const char *pszXML) { CPLXMLNode *psTree; OGRErr eErr = OGRERR_UNSUPPORTED_SRS; this->Clear(); /* -------------------------------------------------------------------- */ /* Parse the XML. */ /* -------------------------------------------------------------------- */ psTree = CPLParseXMLString(pszXML); if (psTree == NULL) return OGRERR_CORRUPT_DATA; CPLStripXMLNamespace(psTree, "gml", TRUE); /* -------------------------------------------------------------------- */ /* Import according to the root node type. We walk through */ /* root elements as there is sometimes prefix stuff like */ /* <?xml>. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psNode = psTree; for (psNode = psTree; psNode != NULL; psNode = psNode->psNext) { if (EQUAL(psNode->pszValue, "GeographicCRS")) { eErr = importGeogCSFromXML(this, psNode); break; } else if (EQUAL(psNode->pszValue, "ProjectedCRS")) { eErr = importProjCSFromXML(this, psNode); break; } } CPLDestroyXMLNode(psTree); return eErr; }
void BAGDataset::LoadMetadata() { /* -------------------------------------------------------------------- */ /* Load the metadata from the file. */ /* -------------------------------------------------------------------- */ hid_t hMDDS = H5Dopen( hHDF5, "/BAG_root/metadata" ); hid_t datatype = H5Dget_type( hMDDS ); hid_t dataspace = H5Dget_space( hMDDS ); hid_t native = H5Tget_native_type( datatype, H5T_DIR_ASCEND ); hsize_t dims[3], maxdims[3]; H5Sget_simple_extent_dims( dataspace, dims, maxdims ); pszXMLMetadata = (char *) CPLCalloc(dims[0]+1,1); H5Dread( hMDDS, native, H5S_ALL, dataspace, H5P_DEFAULT, pszXMLMetadata ); H5Sclose( dataspace ); H5Tclose( datatype ); H5Dclose( hMDDS ); if( strlen(pszXMLMetadata) == 0 ) return; /* -------------------------------------------------------------------- */ /* Try to get the geotransform. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psRoot = CPLParseXMLString( pszXMLMetadata ); if( psRoot == NULL ) return; CPLStripXMLNamespace( psRoot, NULL, TRUE ); CPLXMLNode *psGeo = CPLSearchXMLNode( psRoot, "=MD_Georectified" ); if( psGeo != NULL ) { char **papszCornerTokens = CSLTokenizeStringComplex( CPLGetXMLValue( psGeo, "cornerPoints.Point.coordinates", "" ), " ,", FALSE, FALSE ); if( CSLCount(papszCornerTokens ) == 4 ) { double dfLLX = atof( papszCornerTokens[0] ); double dfLLY = atof( papszCornerTokens[1] ); double dfURX = atof( papszCornerTokens[2] ); double dfURY = atof( papszCornerTokens[3] ); adfGeoTransform[0] = dfLLX; adfGeoTransform[1] = (dfURX - dfLLX) / (GetRasterXSize()-1); adfGeoTransform[3] = dfURY; adfGeoTransform[5] = (dfLLY - dfURY) / (GetRasterYSize()-1); adfGeoTransform[0] -= adfGeoTransform[1] * 0.5; adfGeoTransform[3] -= adfGeoTransform[5] * 0.5; } CSLDestroy( papszCornerTokens ); } CPLDestroyXMLNode( psRoot ); /* -------------------------------------------------------------------- */ /* Try to get the coordinate system. */ /* -------------------------------------------------------------------- */ OGRSpatialReference oSRS; if( OGR_SRS_ImportFromISO19115( &oSRS, pszXMLMetadata ) == OGRERR_NONE ) { oSRS.exportToWkt( &pszProjection ); } }
int GMLParseXSD( const char *pszFile, std::vector<GMLFeatureClass*> & aosClasses) { if( pszFile == NULL ) return FALSE; /* -------------------------------------------------------------------- */ /* Load the raw XML file. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psXSDTree = CPLParseXMLFile( pszFile ); if( psXSDTree == NULL ) return FALSE; /* -------------------------------------------------------------------- */ /* Strip off any namespace qualifiers. */ /* -------------------------------------------------------------------- */ CPLStripXMLNamespace( psXSDTree, NULL, TRUE ); /* -------------------------------------------------------------------- */ /* Find <schema> root element. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psSchemaNode = CPLGetXMLNode( psXSDTree, "=schema" ); if( psSchemaNode == NULL ) { CPLDestroyXMLNode( psXSDTree ); return FALSE; } /* ==================================================================== */ /* Process each feature class definition. */ /* ==================================================================== */ CPLXMLNode *psThis; for( psThis = psSchemaNode->psChild; psThis != NULL; psThis = psThis->psNext ) { /* -------------------------------------------------------------------- */ /* Check for <xs:element> node. */ /* -------------------------------------------------------------------- */ if( psThis->eType != CXT_Element || !EQUAL(psThis->pszValue,"element") ) continue; /* -------------------------------------------------------------------- */ /* Check the substitution group. */ /* -------------------------------------------------------------------- */ const char *pszSubGroup = StripNS(CPLGetXMLValue(psThis,"substitutionGroup","")); // Old OGR produced elements for the feature collection. if( EQUAL(pszSubGroup, "_FeatureCollection") ) continue; if( !EQUAL(pszSubGroup, "_Feature") && !EQUAL(pszSubGroup, "AbstractFeature") /* AbstractFeature used by GML 3.2 */ ) { continue; } /* -------------------------------------------------------------------- */ /* Get name */ /* -------------------------------------------------------------------- */ const char *pszName; pszName = CPLGetXMLValue( psThis, "name", NULL ); if( pszName == NULL ) { continue; } /* -------------------------------------------------------------------- */ /* Get type and verify relationship with name. */ /* -------------------------------------------------------------------- */ const char *pszType; pszType = CPLGetXMLValue( psThis, "type", NULL ); if (pszType == NULL) { CPLXMLNode *psComplexType = CPLGetXMLNode( psThis, "complexType" ); if (psComplexType) { GMLFeatureClass* poClass = GMLParseFeatureType(psSchemaNode, pszName, psComplexType); if (poClass) aosClasses.push_back(poClass); } continue; } if( strstr( pszType, ":" ) != NULL ) pszType = strstr( pszType, ":" ) + 1; if( EQUAL(pszType, pszName) ) { /* A few WFS servers return a type name which is the element name */ /* without any _Type or Type suffix */ /* e.g. : http://apollo.erdas.com/erdas-apollo/vector/Cherokee?SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType&TYPENAME=iwfs:Air */ } else if( !EQUALN(pszType,pszName,strlen(pszName)) || !(EQUAL(pszType+strlen(pszName),"_Type") || EQUAL(pszType+strlen(pszName),"Type")) ) { continue; } /* CanVec .xsd contains weird types that are not used in the related GML */ if (strncmp(pszName, "XyZz", 4) == 0 || strncmp(pszName, "XyZ1", 4) == 0 || strncmp(pszName, "XyZ2", 4) == 0) continue; GMLFeatureClass* poClass = GMLParseFeatureType(psSchemaNode, pszName, pszType); if (poClass) aosClasses.push_back(poClass); } CPLDestroyXMLNode( psXSDTree ); if( aosClasses.size() > 0 ) { return TRUE; } else return FALSE; }
OGRErr BAGDataset::ParseWKTFromXML( const char *pszISOXML ) { OGRSpatialReference oSRS; CPLXMLNode *psRoot = CPLParseXMLString( pszISOXML ); OGRErr eOGRErr = OGRERR_FAILURE; if( psRoot == NULL ) return eOGRErr; CPLStripXMLNamespace( psRoot, NULL, TRUE ); CPLXMLNode *psRSI = CPLSearchXMLNode( psRoot, "=referenceSystemInfo" ); if( psRSI == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Unable to find <referenceSystemInfo> in metadata." ); CPLDestroyXMLNode( psRoot ); return eOGRErr; } oSRS.Clear(); const char *pszSRCodeString = CPLGetXMLValue( psRSI, "MD_ReferenceSystem.referenceSystemIdentifier.RS_Identifier.code.CharacterString", NULL ); if( pszSRCodeString == NULL ) { CPLDebug("BAG", "Unable to find /MI_Metadata/referenceSystemInfo[1]/MD_ReferenceSystem[1]/referenceSystemIdentifier[1]/RS_Identifier[1]/code[1]/CharacterString[1] in metadata." ); CPLDestroyXMLNode( psRoot ); return eOGRErr; } const char *pszSRCodeSpace = CPLGetXMLValue( psRSI, "MD_ReferenceSystem.referenceSystemIdentifier.RS_Identifier.codeSpace.CharacterString", "" ); if( !EQUAL( pszSRCodeSpace, "WKT" ) ) { CPLError( CE_Failure, CPLE_AppDefined, "Spatial reference string is not in WKT." ); CPLDestroyXMLNode( psRoot ); return eOGRErr; } char* pszWKT = const_cast< char* >( pszSRCodeString ); if( oSRS.importFromWkt( &pszWKT ) != OGRERR_NONE ) { CPLError( CE_Failure, CPLE_AppDefined, "Failed parsing WKT string \"%s\".", pszSRCodeString ); CPLDestroyXMLNode( psRoot ); return eOGRErr; } oSRS.exportToWkt( &pszProjection ); eOGRErr = OGRERR_NONE; psRSI = CPLSearchXMLNode( psRSI->psNext, "=referenceSystemInfo" ); if( psRSI == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Unable to find second instance of <referenceSystemInfo> in metadata." ); CPLDestroyXMLNode( psRoot ); return eOGRErr; } pszSRCodeString = CPLGetXMLValue( psRSI, "MD_ReferenceSystem.referenceSystemIdentifier.RS_Identifier.code.CharacterString", NULL ); if( pszSRCodeString == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Unable to find /MI_Metadata/referenceSystemInfo[2]/MD_ReferenceSystem[1]/referenceSystemIdentifier[1]/RS_Identifier[1]/code[1]/CharacterString[1] in metadata." ); CPLDestroyXMLNode( psRoot ); return eOGRErr; } pszSRCodeSpace = CPLGetXMLValue( psRSI, "MD_ReferenceSystem.referenceSystemIdentifier.RS_Identifier.codeSpace.CharacterString", "" ); if( !EQUAL( pszSRCodeSpace, "WKT" ) ) { CPLError( CE_Failure, CPLE_AppDefined, "Spatial reference string is not in WKT." ); CPLDestroyXMLNode( psRoot ); return eOGRErr; } if( EQUALN(pszSRCodeString, "VERTCS", 6 ) ) { CPLString oString( pszProjection ); oString += ","; oString += pszSRCodeString; if ( pszProjection ) CPLFree( pszProjection ); pszProjection = CPLStrdup( oString ); } CPLDestroyXMLNode( psRoot ); return eOGRErr; }
int GDALJP2Metadata::ParseGMLCoverageDesc() { /* -------------------------------------------------------------------- */ /* Do we have an XML doc that is apparently a coverage */ /* description? */ /* -------------------------------------------------------------------- */ const char *pszCoverage = CSLFetchNameValue( papszGMLMetadata, "gml.root-instance" ); if( pszCoverage == NULL ) return FALSE; CPLDebug( "GDALJP2Metadata", "Found GML Box:\n%s", pszCoverage ); /* -------------------------------------------------------------------- */ /* Try parsing the XML. Wipe any namespace prefixes. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psXML = CPLParseXMLString( pszCoverage ); if( psXML == NULL ) return FALSE; CPLStripXMLNamespace( psXML, NULL, TRUE ); /* -------------------------------------------------------------------- */ /* Isolate RectifiedGrid. Eventually we will need to support */ /* other georeferencing objects. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psRG = CPLSearchXMLNode( psXML, "=RectifiedGrid" ); CPLXMLNode *psOriginPoint = NULL; const char *pszOffset1=NULL, *pszOffset2=NULL; if( psRG != NULL ) { psOriginPoint = CPLGetXMLNode( psRG, "origin.Point" ); CPLXMLNode *psOffset1 = CPLGetXMLNode( psRG, "offsetVector" ); if( psOffset1 != NULL ) { pszOffset1 = CPLGetXMLValue( psOffset1, "", NULL ); pszOffset2 = CPLGetXMLValue( psOffset1->psNext, "=offsetVector", NULL ); } } /* -------------------------------------------------------------------- */ /* If we are missing any of the origin or 2 offsets then give up. */ /* -------------------------------------------------------------------- */ if( psOriginPoint == NULL || pszOffset1 == NULL || pszOffset2 == NULL ) { CPLDestroyXMLNode( psXML ); return FALSE; } /* -------------------------------------------------------------------- */ /* Extract origin location. */ /* -------------------------------------------------------------------- */ OGRPoint *poOriginGeometry = NULL; const char *pszSRSName = NULL; if( psOriginPoint != NULL ) { poOriginGeometry = (OGRPoint *) OGR_G_CreateFromGMLTree( psOriginPoint ); if( poOriginGeometry != NULL && wkbFlatten(poOriginGeometry->getGeometryType()) != wkbPoint ) { delete poOriginGeometry; poOriginGeometry = NULL; } // SRS? pszSRSName = CPLGetXMLValue( psOriginPoint, "srsName", NULL ); } /* -------------------------------------------------------------------- */ /* Extract offset(s) */ /* -------------------------------------------------------------------- */ char **papszOffset1Tokens = NULL; char **papszOffset2Tokens = NULL; int bSuccess = FALSE; papszOffset1Tokens = CSLTokenizeStringComplex( pszOffset1, " ,", FALSE, FALSE ); papszOffset2Tokens = CSLTokenizeStringComplex( pszOffset2, " ,", FALSE, FALSE ); if( CSLCount(papszOffset1Tokens) >= 2 && CSLCount(papszOffset2Tokens) >= 2 && poOriginGeometry != NULL ) { adfGeoTransform[0] = poOriginGeometry->getX(); adfGeoTransform[1] = atof(papszOffset1Tokens[0]); adfGeoTransform[2] = atof(papszOffset2Tokens[0]); adfGeoTransform[3] = poOriginGeometry->getY(); adfGeoTransform[4] = atof(papszOffset1Tokens[1]); adfGeoTransform[5] = atof(papszOffset2Tokens[1]); // offset from center of pixel. adfGeoTransform[0] -= adfGeoTransform[1]*0.5; adfGeoTransform[0] -= adfGeoTransform[2]*0.5; adfGeoTransform[3] -= adfGeoTransform[4]*0.5; adfGeoTransform[3] -= adfGeoTransform[5]*0.5; bSuccess = TRUE; bHaveGeoTransform = TRUE; } CSLDestroy( papszOffset1Tokens ); CSLDestroy( papszOffset2Tokens ); if( poOriginGeometry != NULL ) delete poOriginGeometry; /* -------------------------------------------------------------------- */ /* If we still don't have an srsName, check for it on the */ /* boundedBy Envelope. Some products */ /* (ie. EuropeRasterTile23.jpx) use this as the only srsName */ /* delivery vehicle. */ /* -------------------------------------------------------------------- */ if( pszSRSName == NULL ) { pszSRSName = CPLGetXMLValue( psXML, "=FeatureCollection.boundedBy.Envelope.srsName", NULL ); } /* -------------------------------------------------------------------- */ /* If we have gotten a geotransform, then try to interprete the */ /* srsName. */ /* -------------------------------------------------------------------- */ int bNeedAxisFlip = FALSE; if( bSuccess && pszSRSName != NULL && (pszProjection == NULL || strlen(pszProjection) == 0) ) { OGRSpatialReference oSRS; if( EQUALN(pszSRSName,"epsg:",5) ) { if( oSRS.SetFromUserInput( pszSRSName ) == OGRERR_NONE ) oSRS.exportToWkt( &pszProjection ); } else if( EQUALN(pszSRSName,"urn:",4) && strstr(pszSRSName,":def:") != NULL && oSRS.importFromURN(pszSRSName) == OGRERR_NONE ) { const char *pszCode = strrchr(pszSRSName,':') + 1; oSRS.exportToWkt( &pszProjection ); // Per #2131 if( atoi(pszCode) >= 4000 && atoi(pszCode) <= 4999 ) { CPLDebug( "GMLJP2", "Request axis flip for SRS=%s", pszSRSName ); bNeedAxisFlip = TRUE; } } else if( !GMLSRSLookup( pszSRSName ) ) { CPLDebug( "GDALJP2Metadata", "Unable to evaluate SRSName=%s", pszSRSName ); } } if( pszProjection ) CPLDebug( "GDALJP2Metadata", "Got projection from GML box: %s", pszProjection ); CPLDestroyXMLNode( psXML ); psXML = NULL; /* -------------------------------------------------------------------- */ /* Do we need to flip the axes? */ /* -------------------------------------------------------------------- */ if( bNeedAxisFlip && CSLTestBoolean( CPLGetConfigOption( "GDAL_IGNORE_AXIS_ORIENTATION", "FALSE" ) ) ) { bNeedAxisFlip = FALSE; CPLDebug( "GMLJP2", "Supressed axis flipping based on GDAL_IGNORE_AXIS_ORIENTATION." ); } if( bNeedAxisFlip ) { double dfTemp; CPLDebug( "GMLJP2", "Flipping axis orientation in GMLJP2 coverage description." ); dfTemp = adfGeoTransform[0]; adfGeoTransform[0] = adfGeoTransform[3]; adfGeoTransform[3] = dfTemp; dfTemp = adfGeoTransform[1]; adfGeoTransform[1] = adfGeoTransform[4]; adfGeoTransform[4] = dfTemp; dfTemp = adfGeoTransform[2]; adfGeoTransform[2] = adfGeoTransform[5]; adfGeoTransform[5] = dfTemp; } return pszProjection != NULL && bSuccess; }
static CPLXMLNode * GetDictionaryItem( char **papszGMLMetadata, const char *pszURN ) { char *pszLabel; const char *pszFragmentId = NULL; int i; if( EQUALN(pszURN,"urn:jp2k:xml:", 13) ) pszLabel = CPLStrdup( pszURN + 13 ); else if( EQUALN(pszURN,"urn:ogc:tc:gmljp2:xml:", 22) ) pszLabel = CPLStrdup( pszURN + 22 ); else if( EQUALN(pszURN,"gmljp2://xml/",13) ) pszLabel = CPLStrdup( pszURN + 13 ); else pszLabel = CPLStrdup( pszURN ); /* -------------------------------------------------------------------- */ /* Split out label and fragment id. */ /* -------------------------------------------------------------------- */ for( i = 0; pszLabel[i] != '#'; i++ ) { if( pszLabel[i] == '\0' ) return NULL; } pszFragmentId = pszLabel + i + 1; pszLabel[i] = '\0'; /* -------------------------------------------------------------------- */ /* Can we find an XML box with the desired label? */ /* -------------------------------------------------------------------- */ const char *pszDictionary = CSLFetchNameValue( papszGMLMetadata, pszLabel ); if( pszDictionary == NULL ) return NULL; /* -------------------------------------------------------------------- */ /* Try and parse the dictionary. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psDictTree = CPLParseXMLString( pszDictionary ); if( psDictTree == NULL ) { CPLDestroyXMLNode( psDictTree ); return NULL; } CPLStripXMLNamespace( psDictTree, NULL, TRUE ); CPLXMLNode *psDictRoot = CPLSearchXMLNode( psDictTree, "=Dictionary" ); if( psDictRoot == NULL ) { CPLDestroyXMLNode( psDictTree ); return NULL; } /* -------------------------------------------------------------------- */ /* Search for matching id. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psEntry, *psHit = NULL; for( psEntry = psDictRoot->psChild; psEntry != NULL && psHit == NULL; psEntry = psEntry->psNext ) { const char *pszId; if( psEntry->eType != CXT_Element ) continue; if( !EQUAL(psEntry->pszValue,"dictionaryEntry") ) continue; if( psEntry->psChild == NULL ) continue; pszId = CPLGetXMLValue( psEntry->psChild, "id", "" ); if( EQUAL(pszId, pszFragmentId) ) psHit = CPLCloneXMLTree( psEntry->psChild ); } /* -------------------------------------------------------------------- */ /* Cleanup */ /* -------------------------------------------------------------------- */ CPLFree( pszLabel ); CPLDestroyXMLNode( psDictTree ); return psHit; }
OGRErr OGR_SRS_ImportFromISO19115( OGRSpatialReference *poThis, const char *pszISOXML ) { /* -------------------------------------------------------------------- */ /* Parse the XML into tree form. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psRoot = CPLParseXMLString( pszISOXML ); if( psRoot == NULL ) return OGRERR_FAILURE; CPLStripXMLNamespace( psRoot, NULL, TRUE ); /* -------------------------------------------------------------------- */ /* For now we look for projection codes recognised in the BAG */ /* format (see ons_fsd.pdf: Metadata Dataset Character String */ /* Constants). */ /* -------------------------------------------------------------------- */ CPLXMLNode *psRSI = CPLSearchXMLNode( psRoot, "=referenceSystemInfo" ); if( psRSI == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Unable to find <referenceSystemInfo> in metadata." ); CPLDestroyXMLNode( psRoot ); return OGRERR_FAILURE; } poThis->Clear(); /* -------------------------------------------------------------------- */ /* First, set the datum. */ /* -------------------------------------------------------------------- */ const char *pszDatum = CPLGetXMLValue( psRSI, "MD_CRS.datum.RS_Identifier.code", "" ); if( strlen(pszDatum) > 0 && poThis->SetWellKnownGeogCS( pszDatum ) != OGRERR_NONE ) { CPLDestroyXMLNode( psRoot ); return OGRERR_FAILURE; } /* -------------------------------------------------------------------- */ /* Then try to extract the projection. */ /* -------------------------------------------------------------------- */ const char *pszProjection = CPLGetXMLValue( psRSI, "MD_CRS.projection.RS_Identifier.code", "" ); if( EQUAL(pszProjection,"UTM") ) { int nZone = atoi(CPLGetXMLValue( psRSI, "MD_CRS.projectionParameters.MD_ProjectionParameters.zone", "0" )); poThis->SetUTM( ABS(nZone), nZone > 0 ); } else if( EQUAL(pszProjection,"Geodetic") ) { const char *pszEllipsoid = CPLGetXMLValue( psRSI, "MD_CRS.ellipsoid.RS_Identifier.code", "" ); if( !EQUAL(pszDatum, "WGS84") || !EQUAL(pszEllipsoid, "WGS84") ) { CPLError( CE_Failure, CPLE_AppDefined, "ISO 19115 parser does not support custom GCS." ); CPLDestroyXMLNode( psRoot ); return OGRERR_FAILURE; } } else { CPLError( CE_Failure, CPLE_AppDefined, "projection = %s not recognised by ISO 19115 parser.", pszProjection ); CPLDestroyXMLNode( psRoot ); return OGRERR_FAILURE; } CPLDestroyXMLNode( psRoot ); return OGRERR_NONE; }
void BAGDataset::LoadMetadata() { // Load the metadata from the file. const hid_t hMDDS = H5Dopen(hHDF5, "/BAG_root/metadata"); const hid_t datatype = H5Dget_type(hMDDS); const hid_t dataspace = H5Dget_space(hMDDS); const hid_t native = H5Tget_native_type(datatype, H5T_DIR_ASCEND); hsize_t dims[3] = { static_cast<hsize_t>(0), static_cast<hsize_t>(0), static_cast<hsize_t>(0) }; hsize_t maxdims[3] = { static_cast<hsize_t>(0), static_cast<hsize_t>(0), static_cast<hsize_t>(0) }; H5Sget_simple_extent_dims(dataspace, dims, maxdims); pszXMLMetadata = static_cast<char *>(CPLCalloc(static_cast<int>(dims[0] + 1), 1)); H5Dread(hMDDS, native, H5S_ALL, dataspace, H5P_DEFAULT, pszXMLMetadata); H5Tclose(native); H5Sclose(dataspace); H5Tclose(datatype); H5Dclose(hMDDS); if( strlen(pszXMLMetadata) == 0 ) return; // Try to get the geotransform. CPLXMLNode *psRoot = CPLParseXMLString(pszXMLMetadata); if( psRoot == nullptr ) return; CPLStripXMLNamespace(psRoot, nullptr, TRUE); CPLXMLNode *const psGeo = CPLSearchXMLNode(psRoot, "=MD_Georectified"); if( psGeo != nullptr ) { char **papszCornerTokens = CSLTokenizeStringComplex( CPLGetXMLValue(psGeo, "cornerPoints.Point.coordinates", ""), " ,", FALSE, FALSE); if( CSLCount(papszCornerTokens) == 4 ) { const double dfLLX = CPLAtof(papszCornerTokens[0]); const double dfLLY = CPLAtof(papszCornerTokens[1]); const double dfURX = CPLAtof(papszCornerTokens[2]); const double dfURY = CPLAtof(papszCornerTokens[3]); adfGeoTransform[0] = dfLLX; adfGeoTransform[1] = (dfURX - dfLLX) / (GetRasterXSize() - 1); adfGeoTransform[3] = dfURY; adfGeoTransform[5] = (dfLLY - dfURY) / (GetRasterYSize() - 1); adfGeoTransform[0] -= adfGeoTransform[1] * 0.5; adfGeoTransform[3] -= adfGeoTransform[5] * 0.5; } CSLDestroy(papszCornerTokens); } // Try to get the coordinate system. OGRSpatialReference oSRS; if( OGR_SRS_ImportFromISO19115(&oSRS, pszXMLMetadata) == OGRERR_NONE ) { oSRS.exportToWkt(&pszProjection); } else { ParseWKTFromXML(pszXMLMetadata); } // Fetch acquisition date. CPLXMLNode *const psDateTime = CPLSearchXMLNode(psRoot, "=dateTime"); if( psDateTime != nullptr ) { const char *pszDateTimeValue = CPLGetXMLValue(psDateTime, nullptr, ""); if( pszDateTimeValue ) SetMetadataItem("BAG_DATETIME", pszDateTimeValue); } CPLDestroyXMLNode(psRoot); }
CPLErr GDALParseGMLCoverage( CPLXMLNode *psXML, int *pnXSize, int *pnYSize, double *padfGeoTransform, char **ppszProjection ) { CPLStripXMLNamespace( psXML, NULL, TRUE ); /* -------------------------------------------------------------------- */ /* Isolate RectifiedGrid. Eventually we will need to support */ /* other georeferencing objects. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psRG = CPLSearchXMLNode( psXML, "=RectifiedGrid" ); CPLXMLNode *psOriginPoint = NULL; const char *pszOffset1=NULL, *pszOffset2=NULL; if( psRG != NULL ) { psOriginPoint = CPLGetXMLNode( psRG, "origin.Point" ); if( psOriginPoint == NULL ) psOriginPoint = CPLGetXMLNode( psRG, "origin" ); CPLXMLNode *psOffset1 = CPLGetXMLNode( psRG, "offsetVector" ); if( psOffset1 != NULL ) { pszOffset1 = CPLGetXMLValue( psOffset1, "", NULL ); pszOffset2 = CPLGetXMLValue( psOffset1->psNext, "=offsetVector", NULL ); } } /* -------------------------------------------------------------------- */ /* If we are missing any of the origin or 2 offsets then give up. */ /* -------------------------------------------------------------------- */ if( psRG == NULL || psOriginPoint == NULL || pszOffset1 == NULL || pszOffset2 == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Unable to find GML RectifiedGrid, origin or offset vectors"); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Search for the GridEnvelope and derive the raster size. */ /* -------------------------------------------------------------------- */ char **papszLow = CSLTokenizeString( CPLGetXMLValue( psRG, "limits.GridEnvelope.low", "")); char **papszHigh = CSLTokenizeString( CPLGetXMLValue( psRG, "limits.GridEnvelope.high","")); if( CSLCount(papszLow) < 2 || CSLCount(papszHigh) < 2 ) { CPLError( CE_Failure, CPLE_AppDefined, "Unable to find or parse GridEnvelope.low/high." ); return CE_Failure; } if( pnXSize != NULL ) *pnXSize = atoi(papszHigh[0]) - atoi(papszLow[0]) + 1; if( pnYSize != NULL ) *pnYSize = atoi(papszHigh[1]) - atoi(papszLow[1]) + 1; CSLDestroy( papszLow ); CSLDestroy( papszHigh ); /* -------------------------------------------------------------------- */ /* Extract origin location. */ /* -------------------------------------------------------------------- */ OGRPoint *poOriginGeometry = NULL; const char *pszSRSName = NULL; if( psOriginPoint != NULL ) { int bOldWrap = FALSE; // old coverages (ie. WCS) just have <pos> under <origin> so we // may need to temporarily force <origin> to <Point> if( psOriginPoint->eType == CXT_Element && EQUAL(psOriginPoint->pszValue,"origin") ) { strcpy( psOriginPoint->pszValue, "Point"); bOldWrap = TRUE; } poOriginGeometry = (OGRPoint *) OGR_G_CreateFromGMLTree( psOriginPoint ); if( poOriginGeometry != NULL && wkbFlatten(poOriginGeometry->getGeometryType()) != wkbPoint ) { delete poOriginGeometry; poOriginGeometry = NULL; } if( bOldWrap ) strcpy( psOriginPoint->pszValue, "origin"); // SRS? pszSRSName = CPLGetXMLValue( psOriginPoint, "srsName", NULL ); } /* -------------------------------------------------------------------- */ /* Extract offset(s) */ /* -------------------------------------------------------------------- */ char **papszOffset1Tokens = NULL; char **papszOffset2Tokens = NULL; int bSuccess = FALSE; papszOffset1Tokens = CSLTokenizeStringComplex( pszOffset1, " ,", FALSE, FALSE ); papszOffset2Tokens = CSLTokenizeStringComplex( pszOffset2, " ,", FALSE, FALSE ); if( CSLCount(papszOffset1Tokens) >= 2 && CSLCount(papszOffset2Tokens) >= 2 && poOriginGeometry != NULL ) { padfGeoTransform[0] = poOriginGeometry->getX(); padfGeoTransform[1] = atof(papszOffset1Tokens[0]); padfGeoTransform[2] = atof(papszOffset1Tokens[1]); padfGeoTransform[3] = poOriginGeometry->getY(); padfGeoTransform[4] = atof(papszOffset2Tokens[0]); padfGeoTransform[5] = atof(papszOffset2Tokens[1]); // offset from center of pixel. padfGeoTransform[0] -= padfGeoTransform[1]*0.5; padfGeoTransform[0] -= padfGeoTransform[2]*0.5; padfGeoTransform[3] -= padfGeoTransform[4]*0.5; padfGeoTransform[3] -= padfGeoTransform[5]*0.5; bSuccess = TRUE; //bHaveGeoTransform = TRUE; } CSLDestroy( papszOffset1Tokens ); CSLDestroy( papszOffset2Tokens ); if( poOriginGeometry != NULL ) delete poOriginGeometry; /* -------------------------------------------------------------------- */ /* If we have gotten a geotransform, then try to interprete the */ /* srsName. */ /* -------------------------------------------------------------------- */ if( bSuccess && pszSRSName != NULL && (*ppszProjection == NULL || strlen(*ppszProjection) == 0) ) { if( EQUALN(pszSRSName,"epsg:",5) ) { OGRSpatialReference oSRS; if( oSRS.SetFromUserInput( pszSRSName ) == OGRERR_NONE ) oSRS.exportToWkt( ppszProjection ); } else if( EQUALN(pszSRSName,"urn:ogc:def:crs:",16) ) { OGRSpatialReference oSRS; if( oSRS.importFromURN( pszSRSName ) == OGRERR_NONE ) oSRS.exportToWkt( ppszProjection ); } else *ppszProjection = CPLStrdup(pszSRSName); } if( *ppszProjection ) CPLDebug( "GDALJP2Metadata", "Got projection from GML box: %s", *ppszProjection ); return CE_None; }
int GMLReader::ParseXSD( const char *pszFile ) { if( pszFile == NULL ) return FALSE; /* -------------------------------------------------------------------- */ /* Load the raw XML file. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psXSDTree = CPLParseXMLFile( pszFile ); if( psXSDTree == NULL ) return FALSE; /* -------------------------------------------------------------------- */ /* Strip off any namespace qualifiers. */ /* -------------------------------------------------------------------- */ CPLStripXMLNamespace( psXSDTree, NULL, TRUE ); /* -------------------------------------------------------------------- */ /* Find <schema> root element. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psSchemaNode = CPLGetXMLNode( psXSDTree, "=schema" ); if( psSchemaNode == NULL ) { CPLDestroyXMLNode( psXSDTree ); return FALSE; } /* ==================================================================== */ /* Process each feature class definition. */ /* ==================================================================== */ CPLXMLNode *psThis; int bIsLevel0 = TRUE; for( psThis = psSchemaNode->psChild; psThis != NULL; psThis = psThis->psNext ) { /* -------------------------------------------------------------------- */ /* Check for <xs:element> node. */ /* -------------------------------------------------------------------- */ if( psThis->eType != CXT_Element || !EQUAL(psThis->pszValue,"element") ) continue; /* -------------------------------------------------------------------- */ /* Check the substitution group. */ /* -------------------------------------------------------------------- */ const char *pszSubGroup = StripNS(CPLGetXMLValue(psThis,"substitutionGroup","")); // Old OGR produced elements for the feature collection. if( EQUAL(pszSubGroup, "_FeatureCollection") ) continue; if( !EQUAL(pszSubGroup, "_Feature") ) { bIsLevel0 = FALSE; break; } /* -------------------------------------------------------------------- */ /* Get name */ /* -------------------------------------------------------------------- */ const char *pszName; pszName = CPLGetXMLValue( psThis, "name", NULL ); if( pszName == NULL ) { bIsLevel0 = FALSE; break; } /* -------------------------------------------------------------------- */ /* Get type and verify relationship with name. */ /* -------------------------------------------------------------------- */ const char *pszType; pszType = CPLGetXMLValue( psThis, "type", NULL ); if( strstr( pszType, ":" ) != NULL ) pszType = strstr( pszType, ":" ) + 1; if( pszType == NULL || !EQUALN(pszType,pszName,strlen(pszName)) || !(EQUAL(pszType+strlen(pszName),"_Type") || EQUAL(pszType+strlen(pszName),"Type")) ) { bIsLevel0 = FALSE; break; } /* -------------------------------------------------------------------- */ /* The very next element should be the corresponding */ /* complexType declaration for the element. */ /* -------------------------------------------------------------------- */ psThis = psThis->psNext; while( psThis != NULL && psThis->eType == CXT_Comment ) psThis = psThis->psNext; if( psThis == NULL || psThis->eType != CXT_Element || !EQUAL(psThis->pszValue,"complexType") || !EQUAL(CPLGetXMLValue(psThis,"name",""),pszType) ) { bIsLevel0 = FALSE; break; } /* -------------------------------------------------------------------- */ /* Grab the sequence of extensions greatgrandchild. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psAttrSeq = CPLGetXMLNode( psThis, "complexContent.extension.sequence" ); if( psAttrSeq == NULL ) { bIsLevel0 = FALSE; break; } /* -------------------------------------------------------------------- */ /* We are pretty sure this going to be a valid Feature class */ /* now, so create it. */ /* -------------------------------------------------------------------- */ GMLFeatureClass *poClass = new GMLFeatureClass( pszName ); /* -------------------------------------------------------------------- */ /* Loop over each of the attribute elements being defined for */ /* this feature class. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psAttrDef; for( psAttrDef = psAttrSeq->psChild; psAttrDef != NULL; psAttrDef = psAttrDef->psNext ) { if( !EQUAL(psAttrDef->pszValue,"element") ) continue; // For now we skip geometries .. fixup later. if( CPLGetXMLNode( psAttrDef, "simpleType" ) == NULL ) continue; GMLPropertyDefn *poProp = new GMLPropertyDefn( CPLGetXMLValue( psAttrDef, "name", "unnamed" ), CPLGetXMLValue( psAttrDef, "name", "unnamed" ) ); const char *pszBase = StripNS( CPLGetXMLValue( psAttrDef, "simpleType.restriction.base", "" )); if( EQUAL(pszBase,"decimal") ) { poProp->SetType( GMLPT_Real ); const char *pszWidth = CPLGetXMLValue( psAttrDef, "simpleType.restriction.totalDigits.value", "0" ); const char *pszPrecision = CPLGetXMLValue( psAttrDef, "simpleType.restriction.fractionDigits.value", "0" ); poProp->SetWidth( atoi(pszWidth) ); poProp->SetPrecision( atoi(pszPrecision) ); } else if( EQUAL(pszBase,"float") || EQUAL(pszBase,"double") ) poProp->SetType( GMLPT_Real ); else if( EQUAL(pszBase,"integer") ) { poProp->SetType( GMLPT_Integer ); const char *pszWidth = CPLGetXMLValue( psAttrDef, "simpleType.restriction.totalDigits.value", "0" ); poProp->SetWidth( atoi(pszWidth) ); } else if( EQUAL(pszBase,"string") ) { poProp->SetType( GMLPT_String ); const char *pszWidth = CPLGetXMLValue( psAttrDef, "simpleType.restriction.maxLength.value", "0" ); poProp->SetWidth( atoi(pszWidth) ); } else poProp->SetType( GMLPT_Untyped ); poClass->AddProperty( poProp ); } /* -------------------------------------------------------------------- */ /* Class complete, add to reader class list. */ /* -------------------------------------------------------------------- */ poClass->SetSchemaLocked( TRUE ); AddClass( poClass ); } CPLDestroyXMLNode( psXSDTree ); if( m_nClassCount > 0 ) { SetClassListLocked( TRUE ); return TRUE; } else return FALSE; }
bool GMLParseXSD( const char *pszFile, std::vector<GMLFeatureClass*> & aosClasses, bool& bFullyUnderstood) { bFullyUnderstood = false; if( pszFile == NULL ) return false; /* -------------------------------------------------------------------- */ /* Load the raw XML file. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psXSDTree = GMLParseXMLFile( pszFile ); if( psXSDTree == NULL ) return false; /* -------------------------------------------------------------------- */ /* Strip off any namespace qualifiers. */ /* -------------------------------------------------------------------- */ CPLStripXMLNamespace( psXSDTree, NULL, TRUE ); /* -------------------------------------------------------------------- */ /* Find <schema> root element. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psSchemaNode = CPLGetXMLNode( psXSDTree, "=schema" ); if( psSchemaNode == NULL ) { CPLDestroyXMLNode( psXSDTree ); return false; } /* ==================================================================== */ /* Process each include directive. */ /* ==================================================================== */ CPLXMLSchemaResolveInclude( pszFile, psSchemaNode ); //CPLSerializeXMLTreeToFile(psSchemaNode, "/vsistdout/"); bFullyUnderstood = true; /* ==================================================================== */ /* Process each feature class definition. */ /* ==================================================================== */ CPLXMLNode *psThis = psSchemaNode->psChild; for( ; psThis != NULL; psThis = psThis->psNext ) { /* -------------------------------------------------------------------- */ /* Check for <xs:element> node. */ /* -------------------------------------------------------------------- */ if( psThis->eType != CXT_Element || !EQUAL(psThis->pszValue,"element") ) continue; /* -------------------------------------------------------------------- */ /* Check the substitution group. */ /* -------------------------------------------------------------------- */ const char *pszSubGroup = StripNS(CPLGetXMLValue(psThis,"substitutionGroup","")); // Old OGR produced elements for the feature collection. if( EQUAL(pszSubGroup, "_FeatureCollection") ) continue; if( !EQUAL(pszSubGroup, "_Feature") && !EQUAL(pszSubGroup, "AbstractFeature") /* AbstractFeature used by GML 3.2 */ ) { continue; } /* -------------------------------------------------------------------- */ /* Get name */ /* -------------------------------------------------------------------- */ const char *pszName = CPLGetXMLValue( psThis, "name", NULL ); if( pszName == NULL ) { continue; } /* -------------------------------------------------------------------- */ /* Get type and verify relationship with name. */ /* -------------------------------------------------------------------- */ const char *pszType = CPLGetXMLValue( psThis, "type", NULL ); if (pszType == NULL) { CPLXMLNode *psComplexType = CPLGetXMLNode( psThis, "complexType" ); if (psComplexType) { GMLFeatureClass* poClass = GMLParseFeatureType(psSchemaNode, pszName, psComplexType); if (poClass) aosClasses.push_back(poClass); else bFullyUnderstood = false; } continue; } if( strstr( pszType, ":" ) != NULL ) pszType = strstr( pszType, ":" ) + 1; if( EQUAL(pszType, pszName) ) { /* A few WFS servers return a type name which is the element name */ /* without any _Type or Type suffix */ /* e.g. : http://apollo.erdas.com/erdas-apollo/vector/Cherokee?SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType&TYPENAME=iwfs:Air */ } /* <element name="RekisteriyksikonPalstanTietoja" type="ktjkiiwfs:PalstanTietojaType" substitutionGroup="gml:_Feature" /> */ else if( strlen(pszType) > 4 && strcmp(pszType + strlen(pszType) - 4, "Type") == 0 && strlen(pszName) > strlen(pszType) - 4 && strncmp(pszName + strlen(pszName) - (strlen(pszType) - 4), pszType, strlen(pszType) - 4) == 0 ) { } else if( !EQUALN(pszType,pszName,strlen(pszName)) || !(EQUAL(pszType+strlen(pszName),"_Type") || EQUAL(pszType+strlen(pszName),"Type")) ) { continue; } /* CanVec .xsd contains weird types that are not used in the related GML */ if (STARTS_WITH(pszName, "XyZz") || STARTS_WITH(pszName, "XyZ1") || STARTS_WITH(pszName, "XyZ2")) continue; GMLFeatureClass* poClass = GMLParseFeatureType(psSchemaNode, pszName, pszType); if (poClass) aosClasses.push_back(poClass); else bFullyUnderstood = false; } CPLDestroyXMLNode( psXSDTree ); if( aosClasses.size() > 0 ) { return true; } else return false; }
static void CPLXMLSchemaResolveInclude( const char* pszMainSchemaLocation, CPLXMLNode *psSchemaNode ) { std::set<CPLString> osAlreadyIncluded; bool bTryAgain; do { CPLXMLNode *psLast = NULL; bTryAgain = false; CPLXMLNode *psThis = psSchemaNode->psChild; for( ; psThis != NULL; psThis = psThis->psNext ) { if( psThis->eType == CXT_Element && EQUAL(psThis->pszValue,"include") ) { const char* pszSchemaLocation = CPLGetXMLValue(psThis, "schemaLocation", NULL); if( pszSchemaLocation != NULL && osAlreadyIncluded.count( pszSchemaLocation) == 0 ) { osAlreadyIncluded.insert( pszSchemaLocation ); if( !STARTS_WITH(pszSchemaLocation, "http://") && !STARTS_WITH(pszSchemaLocation, "https://") && CPLIsFilenameRelative(pszSchemaLocation ) ) { pszSchemaLocation = CPLFormFilename( CPLGetPath(pszMainSchemaLocation), pszSchemaLocation, NULL ); } CPLXMLNode *psIncludedXSDTree = GMLParseXMLFile( pszSchemaLocation ); if( psIncludedXSDTree != NULL ) { CPLStripXMLNamespace( psIncludedXSDTree, NULL, TRUE ); CPLXMLNode *psIncludedSchemaNode = CPLGetXMLNode( psIncludedXSDTree, "=schema" ); if( psIncludedSchemaNode != NULL ) { /* Substitute de <include> node by its content */ CPLXMLNode* psFirstChildElement = CPLGetFirstChildNode(psIncludedSchemaNode); if( psFirstChildElement != NULL ) { CPLXMLNode* psCopy = CPLCloneXMLTree(psFirstChildElement); if( psLast != NULL ) psLast->psNext = psCopy; else psSchemaNode->psChild = psCopy; CPLXMLNode* psNext = psThis->psNext; psThis->psNext = NULL; CPLDestroyXMLNode(psThis); psThis = CPLGetLastNode(psCopy); psThis->psNext = psNext; /* In case the included schema also contains */ /* includes */ bTryAgain = true; } } CPLDestroyXMLNode( psIncludedXSDTree ); } } } psLast = psThis; } } while( bTryAgain ); const char* pszSchemaOutputName = CPLGetConfigOption("GML_SCHEMA_OUTPUT_NAME", NULL); if( pszSchemaOutputName != NULL ) { CPLSerializeXMLTreeToFile( psSchemaNode, pszSchemaOutputName ); } }
OGRSpatialReference * WCTSImportCoordinateReferenceSystem( CPLXMLNode *psXMLCRS ) { CPLStripXMLNamespace( psXMLCRS->psChild, NULL, TRUE ); /* ==================================================================== */ /* Try to find a direct crsID as per old specification. */ /* ==================================================================== */ const char *pszCode = CPLGetXMLValue( psXMLCRS, "crsID.code", NULL ); const char *pszCodeSpace = CPLGetXMLValue( psXMLCRS, "crsID.codeSpace", NULL ); if( pszCode != NULL && pszCodeSpace != NULL ) { /* -------------------------------------------------------------------- */ /* Get the EPSG code, and verify that it is in the EPSG */ /* codeSpace. */ /* -------------------------------------------------------------------- */ OGRSpatialReference oSRS; if( EQUAL(pszCodeSpace,"EPSG") ) { int nEPSGCode = atoi(pszCode); if( nEPSGCode == 0 ) { WCTSEmitServiceException( "Failed to decode CoordinateReferenceSystem with missing,\n" "or zero crsID.code" ); } CPLErrorReset(); if( oSRS.importFromEPSG( nEPSGCode ) != OGRERR_NONE ) { if( strlen(CPLGetLastErrorMsg()) > 0 ) WCTSEmitServiceException( CPLGetLastErrorMsg() ); else WCTSEmitServiceException( CPLSPrintf( "OGRSpatialReference::importFromEPSG(%d) " "failed. Is this a defined EPSG code?", nEPSGCode ) ); } } /* -------------------------------------------------------------------- */ /* Handle AUTO case. */ /* -------------------------------------------------------------------- */ else if( EQUAL(pszCodeSpace,"AUTO") ) { if( oSRS.importFromWMSAUTO( pszCode ) != OGRERR_NONE ) { if( strlen(CPLGetLastErrorMsg()) > 0 ) WCTSEmitServiceException( CPLGetLastErrorMsg() ); else WCTSEmitServiceException( CPLSPrintf( "OGRSpatialReference::importFromWMSAUTO(%s) " "failed. Is this a defined EPSG code?", pszCode ) ); } } /* -------------------------------------------------------------------- */ /* Otherwise blow a gasket. */ /* -------------------------------------------------------------------- */ else { WCTSEmitServiceException( "Failed to decode CoordinateReferenceSystem with missing,\n" "or non-EPSG crsID.codeSpace" ); } /* -------------------------------------------------------------------- */ /* Translate into an OGRSpatialReference from EPSG code. */ /* -------------------------------------------------------------------- */ return oSRS.Clone(); } /* ==================================================================== */ /* Try to import a projectedCRS or geographicCRS. */ /* ==================================================================== */ if( CPLGetXMLNode( psXMLCRS, "ProjectedCRS" ) != NULL || CPLGetXMLNode( psXMLCRS, "GeographicCRS" ) != NULL ) { #ifdef DISABLE_USER_DEFINED_CRS WCTSEmitServiceException( "User defined ProjectedCRS and GeographicCRS support\n" "disabled for security reasons." ); #else char *pszSerializedForm; OGRSpatialReference oSRS; pszSerializedForm = CPLSerializeXMLTree( psXMLCRS->psChild ); if( oSRS.importFromXML( pszSerializedForm ) != OGRERR_NONE ) { CPLFree( pszSerializedForm ); if( strlen(CPLGetLastErrorMsg()) > 0 ) WCTSEmitServiceException( CPLGetLastErrorMsg() ); else WCTSEmitServiceException( "Failed to import CRS" ); } CPLFree( pszSerializedForm ); return oSRS.Clone(); #endif } /* -------------------------------------------------------------------- */ /* We don't seem to recognise a CRS here. */ /* -------------------------------------------------------------------- */ WCTSEmitServiceException( "Unable to identify CRS in one of SourceCRS or TargetCRS elements" ); return NULL; }