EVOLUTION-MANAGER
Edit File: wmsmetadataset.cpp
/****************************************************************************** * * Project: WMS Client Driver * Purpose: Definition of GDALWMSMetaDataset class * Author: Even Rouault, <even dot rouault at mines dash paris dot org> * ****************************************************************************** * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org> * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "wmsmetadataset.h" CPL_CVSID("$Id: wmsmetadataset.cpp 36682 2016-12-04 20:34:45Z rouault $"); int VersionStringToInt(const char *version); /************************************************************************/ /* GDALWMSMetaDataset() */ /************************************************************************/ GDALWMSMetaDataset::GDALWMSMetaDataset() : papszSubDatasets(NULL) {} /************************************************************************/ /* ~GDALWMSMetaDataset() */ /************************************************************************/ GDALWMSMetaDataset::~GDALWMSMetaDataset() { CSLDestroy(papszSubDatasets); } /************************************************************************/ /* AddSubDataset() */ /************************************************************************/ void GDALWMSMetaDataset::AddSubDataset(const char* pszName, const char* pszDesc) { char szName[80]; int nCount = CSLCount(papszSubDatasets ) / 2; snprintf( szName, sizeof(szName), "SUBDATASET_%d_NAME", nCount+1 ); papszSubDatasets = CSLSetNameValue( papszSubDatasets, szName, pszName ); snprintf( szName, sizeof(szName), "SUBDATASET_%d_DESC", nCount+1 ); papszSubDatasets = CSLSetNameValue( papszSubDatasets, szName, pszDesc); } /************************************************************************/ /* DownloadGetCapabilities() */ /************************************************************************/ GDALDataset *GDALWMSMetaDataset::DownloadGetCapabilities(GDALOpenInfo *poOpenInfo) { const char* pszURL = poOpenInfo->pszFilename; if (STARTS_WITH_CI(pszURL, "WMS:")) pszURL += 4; CPLString osFormat = CPLURLGetValue(pszURL, "FORMAT"); CPLString osTransparent = CPLURLGetValue(pszURL, "TRANSPARENT"); CPLString osVersion = CPLURLGetValue(pszURL, "VERSION"); CPLString osPreferredSRS = CPLURLGetValue(pszURL, "SRS"); if( osPreferredSRS.empty() ) osPreferredSRS = CPLURLGetValue(pszURL, "CRS"); if (osVersion.empty()) osVersion = "1.1.1"; CPLString osURL(pszURL); osURL = CPLURLAddKVP(osURL, "SERVICE", "WMS"); osURL = CPLURLAddKVP(osURL, "VERSION", osVersion); osURL = CPLURLAddKVP(osURL, "REQUEST", "GetCapabilities"); /* Remove all other keywords */ osURL = CPLURLAddKVP(osURL, "LAYERS", NULL); osURL = CPLURLAddKVP(osURL, "SRS", NULL); osURL = CPLURLAddKVP(osURL, "CRS", NULL); osURL = CPLURLAddKVP(osURL, "BBOX", NULL); osURL = CPLURLAddKVP(osURL, "FORMAT", NULL); osURL = CPLURLAddKVP(osURL, "TRANSPARENT", NULL); osURL = CPLURLAddKVP(osURL, "STYLES", NULL); osURL = CPLURLAddKVP(osURL, "WIDTH", NULL); osURL = CPLURLAddKVP(osURL, "HEIGHT", NULL); CPLHTTPResult* psResult = CPLHTTPFetch( osURL, NULL ); if (psResult == NULL) { return NULL; } if (psResult->nStatus != 0 || psResult->pszErrBuf != NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s (%d)", (psResult->pszErrBuf) ? psResult->pszErrBuf : "unknown", psResult->nStatus); CPLHTTPDestroyResult(psResult); return NULL; } if (psResult->pabyData == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Empty content returned by server"); CPLHTTPDestroyResult(psResult); return NULL; } CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData ); if (psXML == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s", psResult->pabyData); CPLHTTPDestroyResult(psResult); return NULL; } GDALDataset* poRet = AnalyzeGetCapabilities(psXML, osFormat, osTransparent, osPreferredSRS); CPLHTTPDestroyResult(psResult); CPLDestroyXMLNode( psXML ); return poRet; } /************************************************************************/ /* DownloadGetTileService() */ /************************************************************************/ GDALDataset *GDALWMSMetaDataset::DownloadGetTileService(GDALOpenInfo *poOpenInfo) { const char* pszURL = poOpenInfo->pszFilename; if (STARTS_WITH_CI(pszURL, "WMS:")) pszURL += 4; CPLString osURL(pszURL); osURL = CPLURLAddKVP(osURL, "SERVICE", "WMS"); osURL = CPLURLAddKVP(osURL, "REQUEST", "GetTileService"); /* Remove all other keywords */ osURL = CPLURLAddKVP(osURL, "VERSION", NULL); osURL = CPLURLAddKVP(osURL, "LAYERS", NULL); osURL = CPLURLAddKVP(osURL, "SRS", NULL); osURL = CPLURLAddKVP(osURL, "CRS", NULL); osURL = CPLURLAddKVP(osURL, "BBOX", NULL); osURL = CPLURLAddKVP(osURL, "FORMAT", NULL); osURL = CPLURLAddKVP(osURL, "TRANSPARENT", NULL); osURL = CPLURLAddKVP(osURL, "STYLES", NULL); osURL = CPLURLAddKVP(osURL, "WIDTH", NULL); osURL = CPLURLAddKVP(osURL, "HEIGHT", NULL); CPLHTTPResult* psResult = CPLHTTPFetch( osURL, NULL ); if (psResult == NULL) { return NULL; } if (psResult->nStatus != 0 || psResult->pszErrBuf != NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s (%d)", (psResult->pszErrBuf) ? psResult->pszErrBuf : "unknown", psResult->nStatus); CPLHTTPDestroyResult(psResult); return NULL; } if (psResult->pabyData == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Empty content returned by server"); CPLHTTPDestroyResult(psResult); return NULL; } CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData ); if (psXML == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s", psResult->pabyData); CPLHTTPDestroyResult(psResult); return NULL; } GDALDataset* poRet = AnalyzeGetTileService(psXML); CPLHTTPDestroyResult(psResult); CPLDestroyXMLNode( psXML ); return poRet; } /************************************************************************/ /* GetMetadataDomainList() */ /************************************************************************/ char **GDALWMSMetaDataset::GetMetadataDomainList() { return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(), TRUE, "SUBDATASETS", NULL); } /************************************************************************/ /* GetMetadata() */ /************************************************************************/ char **GDALWMSMetaDataset::GetMetadata( const char *pszDomain ) { if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") ) return papszSubDatasets; return GDALPamDataset::GetMetadata( pszDomain ); } /************************************************************************/ /* AddSubDataset() */ /************************************************************************/ void GDALWMSMetaDataset::AddSubDataset( const char* pszLayerName, const char* pszTitle, CPL_UNUSED const char* pszAbstract, const char* pszSRS, const char* pszMinX, const char* pszMinY, const char* pszMaxX, const char* pszMaxY, CPLString osFormat, CPLString osTransparent) { CPLString osSubdatasetName = "WMS:"; osSubdatasetName += osGetURL; osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "SERVICE", "WMS"); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "VERSION", osVersion); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "REQUEST", "GetMap"); char* pszEscapedLayerName = CPLEscapeString(pszLayerName, -1, CPLES_URL); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "LAYERS", pszEscapedLayerName); CPLFree(pszEscapedLayerName); if(VersionStringToInt(osVersion.c_str())>= VersionStringToInt("1.3.0")) { osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "CRS", pszSRS); /* FIXME: this should apply to all SRS that need axis inversion */ if (strcmp(pszSRS, "EPSG:4326") == 0) osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "BBOXORDER", "yxYX"); } else osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "SRS", pszSRS); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "BBOX", CPLSPrintf("%s,%s,%s,%s", pszMinX, pszMinY, pszMaxX, pszMaxY)); if (!osFormat.empty()) osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "FORMAT", osFormat); if (!osTransparent.empty()) osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "TRANSPARENT", osTransparent); if (pszTitle) { if (!osXMLEncoding.empty() && osXMLEncoding != "utf-8" && osXMLEncoding != "UTF-8") { char* pszRecodedTitle = CPLRecode(pszTitle, osXMLEncoding.c_str(), CPL_ENC_UTF8); if (pszRecodedTitle) AddSubDataset(osSubdatasetName, pszRecodedTitle); else AddSubDataset(osSubdatasetName, pszTitle); CPLFree(pszRecodedTitle); } else { AddSubDataset(osSubdatasetName, pszTitle); } } else { AddSubDataset(osSubdatasetName, pszLayerName); } } /************************************************************************/ /* AddWMSCSubDataset() */ /************************************************************************/ void GDALWMSMetaDataset::AddWMSCSubDataset(WMSCTileSetDesc& oWMSCTileSetDesc, const char* pszTitle, CPLString osTransparent) { CPLString osSubdatasetName = "WMS:"; osSubdatasetName += osGetURL; osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "SERVICE", "WMS"); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "VERSION", osVersion); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "REQUEST", "GetMap"); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "LAYERS", oWMSCTileSetDesc.osLayers); if(VersionStringToInt(osVersion.c_str())>= VersionStringToInt("1.3.0")) osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "CRS", oWMSCTileSetDesc.osSRS); else osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "SRS", oWMSCTileSetDesc.osSRS); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "BBOX", CPLSPrintf("%s,%s,%s,%s", oWMSCTileSetDesc.osMinX.c_str(), oWMSCTileSetDesc.osMinY.c_str(), oWMSCTileSetDesc.osMaxX.c_str(), oWMSCTileSetDesc.osMaxY.c_str())); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "FORMAT", oWMSCTileSetDesc.osFormat); if (!osTransparent.empty()) osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "TRANSPARENT", osTransparent); if (oWMSCTileSetDesc.nTileWidth != oWMSCTileSetDesc.nTileHeight) CPLDebug("WMS", "Weird: nTileWidth != nTileHeight for %s", oWMSCTileSetDesc.osLayers.c_str()); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "TILESIZE", CPLSPrintf("%d", oWMSCTileSetDesc.nTileWidth)); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "OVERVIEWCOUNT", CPLSPrintf("%d", oWMSCTileSetDesc.nResolutions - 1)); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "MINRESOLUTION", CPLSPrintf("%.16f", oWMSCTileSetDesc.dfMinResolution)); osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "TILED", "true"); if (pszTitle) { if (!osXMLEncoding.empty() && osXMLEncoding != "utf-8" && osXMLEncoding != "UTF-8") { char* pszRecodedTitle = CPLRecode(pszTitle, osXMLEncoding.c_str(), CPL_ENC_UTF8); if (pszRecodedTitle) AddSubDataset(osSubdatasetName, pszRecodedTitle); else AddSubDataset(osSubdatasetName, pszTitle); CPLFree(pszRecodedTitle); } else { AddSubDataset(osSubdatasetName, pszTitle); } } else { AddSubDataset(osSubdatasetName, oWMSCTileSetDesc.osLayers); } } /************************************************************************/ /* ExploreLayer() */ /************************************************************************/ void GDALWMSMetaDataset::ExploreLayer(CPLXMLNode* psXML, CPLString osFormat, CPLString osTransparent, CPLString osPreferredSRS, const char* pszSRS, const char* pszMinX, const char* pszMinY, const char* pszMaxX, const char* pszMaxY) { const char* pszName = CPLGetXMLValue(psXML, "Name", NULL); const char* pszTitle = CPLGetXMLValue(psXML, "Title", NULL); const char* pszAbstract = CPLGetXMLValue(psXML, "Abstract", NULL); CPLXMLNode* psSRS = NULL; const char* pszSRSLocal = NULL; const char* pszMinXLocal = NULL; const char* pszMinYLocal = NULL; const char* pszMaxXLocal = NULL; const char* pszMaxYLocal = NULL; const char* pszSRSTagName = VersionStringToInt(osVersion.c_str()) >= VersionStringToInt("1.3.0") ? "CRS" : "SRS"; /* Use local bounding box if available, otherwise use the one */ /* that comes from an upper layer */ /* such as in http://neowms.sci.gsfc.nasa.gov/wms/wms */ CPLXMLNode* psIter = psXML->psChild; while( psIter != NULL ) { if( psIter->eType == CXT_Element && strcmp(psIter->pszValue, "BoundingBox") == 0 ) { psSRS = psIter; pszSRSLocal = CPLGetXMLValue(psSRS, pszSRSTagName, NULL); if( osPreferredSRS.empty() || pszSRSLocal == NULL ) break; if( EQUAL(osPreferredSRS, pszSRSLocal) ) break; psSRS = NULL; pszSRSLocal = NULL; } psIter = psIter->psNext; } if (psSRS == NULL) { psSRS = CPLGetXMLNode( psXML, "LatLonBoundingBox" ); pszSRSLocal = CPLGetXMLValue(psXML, pszSRSTagName, NULL); if (pszSRSLocal == NULL) pszSRSLocal = "EPSG:4326"; } if (pszSRSLocal != NULL && psSRS != NULL) { pszMinXLocal = CPLGetXMLValue(psSRS, "minx", NULL); pszMinYLocal = CPLGetXMLValue(psSRS, "miny", NULL); pszMaxXLocal = CPLGetXMLValue(psSRS, "maxx", NULL); pszMaxYLocal = CPLGetXMLValue(psSRS, "maxy", NULL); if (pszMinXLocal && pszMinYLocal && pszMaxXLocal && pszMaxYLocal) { pszSRS = pszSRSLocal; pszMinX = pszMinXLocal; pszMinY = pszMinYLocal; pszMaxX = pszMaxXLocal; pszMaxY = pszMaxYLocal; } } if (pszName != NULL && pszSRS && pszMinX && pszMinY && pszMaxX && pszMaxY) { CPLString osLocalTransparent(osTransparent); if (osLocalTransparent.empty()) { const char* pszOpaque = CPLGetXMLValue(psXML, "opaque", "0"); if (EQUAL(pszOpaque, "1")) osLocalTransparent = "FALSE"; } WMSCKeyType oWMSCKey(pszName, pszSRS); std::map<WMSCKeyType, WMSCTileSetDesc>::iterator oIter = osMapWMSCTileSet.find(oWMSCKey); if (oIter != osMapWMSCTileSet.end()) { AddWMSCSubDataset(oIter->second, pszTitle, osLocalTransparent); } else { AddSubDataset(pszName, pszTitle, pszAbstract, pszSRS, pszMinX, pszMinY, pszMaxX, pszMaxY, osFormat, osLocalTransparent); } } psIter = psXML->psChild; for(; psIter != NULL; psIter = psIter->psNext) { if (psIter->eType == CXT_Element) { if (EQUAL(psIter->pszValue, "Layer")) ExploreLayer(psIter, osFormat, osTransparent, osPreferredSRS, pszSRS, pszMinX, pszMinY, pszMaxX, pszMaxY); } } } /************************************************************************/ /* ParseWMSCTileSets() */ /************************************************************************/ void GDALWMSMetaDataset::ParseWMSCTileSets(CPLXMLNode* psXML) { CPLXMLNode* psIter = psXML->psChild; for(;psIter;psIter = psIter->psNext) { if (psIter->eType == CXT_Element && EQUAL(psIter->pszValue, "TileSet")) { const char* pszSRS = CPLGetXMLValue(psIter, "SRS", NULL); if (pszSRS == NULL) continue; CPLXMLNode* psBoundingBox = CPLGetXMLNode( psIter, "BoundingBox" ); if (psBoundingBox == NULL) continue; const char* pszMinX = CPLGetXMLValue(psBoundingBox, "minx", NULL); const char* pszMinY = CPLGetXMLValue(psBoundingBox, "miny", NULL); const char* pszMaxX = CPLGetXMLValue(psBoundingBox, "maxx", NULL); const char* pszMaxY = CPLGetXMLValue(psBoundingBox, "maxy", NULL); if (pszMinX == NULL || pszMinY == NULL || pszMaxX == NULL || pszMaxY == NULL) continue; double dfMinX = CPLAtofM(pszMinX); double dfMinY = CPLAtofM(pszMinY); double dfMaxX = CPLAtofM(pszMaxX); double dfMaxY = CPLAtofM(pszMaxY); if (dfMaxY <= dfMinY || dfMaxX <= dfMinX) continue; const char* pszFormat = CPLGetXMLValue( psIter, "Format", NULL ); if (pszFormat == NULL) continue; if (strstr(pszFormat, "kml")) continue; const char* pszTileWidth = CPLGetXMLValue(psIter, "Width", NULL); const char* pszTileHeight = CPLGetXMLValue(psIter, "Height", NULL); if (pszTileWidth == NULL || pszTileHeight == NULL) continue; int nTileWidth = atoi(pszTileWidth); int nTileHeight = atoi(pszTileHeight); if (nTileWidth < 128 || nTileHeight < 128) continue; const char* pszLayers = CPLGetXMLValue(psIter, "Layers", NULL); if (pszLayers == NULL) continue; const char* pszResolutions = CPLGetXMLValue(psIter, "Resolutions", NULL); if (pszResolutions == NULL) continue; char** papszTokens = CSLTokenizeStringComplex(pszResolutions, " ", 0, 0); double dfMinResolution = 0; int i; for(i=0; papszTokens && papszTokens[i]; i++) { double dfResolution = CPLAtofM(papszTokens[i]); if (i==0 || dfResolution < dfMinResolution) dfMinResolution = dfResolution; } CSLDestroy(papszTokens); int nResolutions = i; if (nResolutions == 0) continue; const char* pszStyles = CPLGetXMLValue(psIter, "Styles", ""); /* http://demo.opengeo.org/geoserver/gwc/service/wms?tiled=TRUE&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities */ /* has different variations of formats for the same (formats, SRS) tuple, so just */ /* keep the first one which is a png format */ WMSCKeyType oWMSCKey(pszLayers, pszSRS); std::map<WMSCKeyType, WMSCTileSetDesc>::iterator oIter = osMapWMSCTileSet.find(oWMSCKey); if (oIter != osMapWMSCTileSet.end()) continue; WMSCTileSetDesc oWMSCTileSet; oWMSCTileSet.osLayers = pszLayers; oWMSCTileSet.osSRS = pszSRS; oWMSCTileSet.osMinX = pszMinX; oWMSCTileSet.osMinY = pszMinY; oWMSCTileSet.osMaxX = pszMaxX; oWMSCTileSet.osMaxY = pszMaxY; oWMSCTileSet.dfMinX = dfMinX; oWMSCTileSet.dfMinY = dfMinY; oWMSCTileSet.dfMaxX = dfMaxX; oWMSCTileSet.dfMaxY = dfMaxY; oWMSCTileSet.nResolutions = nResolutions; oWMSCTileSet.dfMinResolution = dfMinResolution; oWMSCTileSet.osFormat = pszFormat; oWMSCTileSet.osStyle = pszStyles; oWMSCTileSet.nTileWidth = nTileWidth; oWMSCTileSet.nTileHeight = nTileHeight; osMapWMSCTileSet[oWMSCKey] = oWMSCTileSet; } } } /************************************************************************/ /* AnalyzeGetCapabilities() */ /************************************************************************/ GDALDataset* GDALWMSMetaDataset::AnalyzeGetCapabilities(CPLXMLNode* psXML, CPLString osFormat, CPLString osTransparent, CPLString osPreferredSRS) { const char* pszEncoding = NULL; if (psXML->eType == CXT_Element && strcmp(psXML->pszValue, "?xml") == 0) pszEncoding = CPLGetXMLValue(psXML, "encoding", NULL); CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=WMT_MS_Capabilities" ); if (psRoot == NULL) psRoot = CPLGetXMLNode( psXML, "=WMS_Capabilities" ); if (psRoot == NULL) return NULL; CPLXMLNode* psCapability = CPLGetXMLNode(psRoot, "Capability"); if (psCapability == NULL) return NULL; CPLXMLNode* psOnlineResource = CPLGetXMLNode(psCapability, "Request.GetMap.DCPType.HTTP.Get.OnlineResource"); if (psOnlineResource == NULL) return NULL; const char* pszGetURL = CPLGetXMLValue(psOnlineResource, "xlink:href", NULL); if (pszGetURL == NULL) return NULL; CPLXMLNode* psLayer = CPLGetXMLNode(psCapability, "Layer"); if (psLayer == NULL) return NULL; CPLXMLNode* psVendorSpecificCapabilities = CPLGetXMLNode(psCapability, "VendorSpecificCapabilities"); GDALWMSMetaDataset* poDS = new GDALWMSMetaDataset(); const char* pszVersion = CPLGetXMLValue(psRoot, "version", NULL); if (pszVersion) poDS->osVersion = pszVersion; else poDS->osVersion = "1.1.1"; poDS->osGetURL = pszGetURL; poDS->osXMLEncoding = pszEncoding ? pszEncoding : ""; if (psVendorSpecificCapabilities) poDS->ParseWMSCTileSets(psVendorSpecificCapabilities); poDS->ExploreLayer(psLayer, osFormat, osTransparent, osPreferredSRS); return poDS; } /************************************************************************/ /* AddTiledSubDataset() */ /************************************************************************/ void GDALWMSMetaDataset::AddTiledSubDataset(const char* pszTiledGroupName, const char* pszTitle) { CPLString osSubdatasetName = "<GDAL_WMS><Service name=\"TiledWMS\"><ServerUrl>"; osSubdatasetName += osGetURL; osSubdatasetName += "</ServerUrl><TiledGroupName>"; osSubdatasetName += pszTiledGroupName; osSubdatasetName += "</TiledGroupName></Service></GDAL_WMS>"; if (pszTitle) { if (!osXMLEncoding.empty() && osXMLEncoding != "utf-8" && osXMLEncoding != "UTF-8") { char* pszRecodedTitle = CPLRecode(pszTitle, osXMLEncoding.c_str(), CPL_ENC_UTF8); if (pszRecodedTitle) AddSubDataset(osSubdatasetName, pszRecodedTitle); else AddSubDataset(osSubdatasetName, pszTitle); CPLFree(pszRecodedTitle); } else { AddSubDataset(osSubdatasetName, pszTitle); } } else { AddSubDataset(osSubdatasetName, pszTiledGroupName); } } /************************************************************************/ /* AnalyzeGetTileServiceRecurse() */ /************************************************************************/ void GDALWMSMetaDataset::AnalyzeGetTileServiceRecurse(CPLXMLNode* psXML) { CPLXMLNode* psIter = psXML->psChild; for(; psIter != NULL; psIter = psIter->psNext) { if (psIter->eType == CXT_Element && EQUAL(psIter->pszValue, "TiledGroup")) { const char* pszName = CPLGetXMLValue(psIter, "Name", NULL); const char* pszTitle = CPLGetXMLValue(psIter, "Title", NULL); if (pszName) AddTiledSubDataset(pszName, pszTitle); } else if (psIter->eType == CXT_Element && EQUAL(psIter->pszValue, "TiledGroups")) { AnalyzeGetTileServiceRecurse(psIter); } } } /************************************************************************/ /* AnalyzeGetTileService() */ /************************************************************************/ GDALDataset* GDALWMSMetaDataset::AnalyzeGetTileService(CPLXMLNode* psXML) { const char* pszEncoding = NULL; if (psXML->eType == CXT_Element && strcmp(psXML->pszValue, "?xml") == 0) pszEncoding = CPLGetXMLValue(psXML, "encoding", NULL); CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=WMS_Tile_Service" ); if (psRoot == NULL) return NULL; CPLXMLNode* psTiledPatterns = CPLGetXMLNode(psRoot, "TiledPatterns"); if (psTiledPatterns == NULL) return NULL; const char* pszURL = CPLGetXMLValue(psTiledPatterns, "OnlineResource.xlink:href", NULL); if (pszURL == NULL) return NULL; GDALWMSMetaDataset* poDS = new GDALWMSMetaDataset(); poDS->osGetURL = pszURL; poDS->osXMLEncoding = pszEncoding ? pszEncoding : ""; poDS->AnalyzeGetTileServiceRecurse(psTiledPatterns); return poDS; } /************************************************************************/ /* AnalyzeTileMapService() */ /************************************************************************/ GDALDataset* GDALWMSMetaDataset::AnalyzeTileMapService(CPLXMLNode* psXML) { CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TileMapService" ); if (psRoot == NULL) return NULL; CPLXMLNode* psTileMaps = CPLGetXMLNode(psRoot, "TileMaps"); if (psTileMaps == NULL) return NULL; GDALWMSMetaDataset* poDS = new GDALWMSMetaDataset(); CPLXMLNode* psIter = psTileMaps->psChild; for(; psIter != NULL; psIter = psIter->psNext) { if (psIter->eType == CXT_Element && EQUAL(psIter->pszValue, "TileMap")) { const char* pszHref = CPLGetXMLValue(psIter, "href", NULL); const char* pszTitle = CPLGetXMLValue(psIter, "title", NULL); if (pszHref && pszTitle) { CPLString osHref(pszHref); const char* pszDup100 = strstr(pszHref, "1.0.0/1.0.0/"); if (pszDup100) { osHref.resize(pszDup100 - pszHref); osHref += pszDup100 + strlen("1.0.0/"); } poDS->AddSubDataset(osHref, pszTitle); } } } return poDS; }