xmlNodePtr msWFSDumpLayer11(mapObj *map, layerObj *lp, xmlNsPtr psNsOws, int nWFSVersion, const char* validate_language) { rectObj ext; xmlNodePtr psRootNode, psNode; const char *value = NULL; char *valueToFree; char **tokens; int n=0,i=0; psRootNode = xmlNewNode(NULL, BAD_CAST "FeatureType"); /* add namespace to layer name */ value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_prefix"); /* FIXME? Should probably be applied to WFS 1.1 as well, but the addition */ /* of the prefix can be disruptive for clients */ if( value == NULL && nWFSVersion >= OWS_2_0_0 ) value = MS_DEFAULT_NAMESPACE_PREFIX; if(value) { n = strlen(value)+strlen(lp->name)+1+1; valueToFree = (char *) msSmallMalloc(sizeof(char*)*n); snprintf(valueToFree, n, "%s%s%s", (value ? value : ""), (value ? ":" : ""), lp->name); psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "Name", BAD_CAST valueToFree); msFree(valueToFree); } else { psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "Name", BAD_CAST lp->name); } if (lp->name && strlen(lp->name) > 0 && (msIsXMLTagValid(lp->name) == MS_FALSE || isdigit(lp->name[0]))) { char szTmp[512]; snprintf(szTmp, sizeof(szTmp), "WARNING: The layer name '%s' might contain spaces or " "invalid characters or may start with a number. This could lead to potential problems", lp->name); xmlAddSibling(psNode, xmlNewComment(BAD_CAST szTmp)); } value = msOWSLookupMetadataWithLanguage(&(lp->metadata), "FO", "title", validate_language); if (!value) value =(const char*)lp->name; psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "Title", BAD_CAST value); value = msOWSLookupMetadataWithLanguage(&(lp->metadata), "FO", "abstract", validate_language); if (value) psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "Abstract", BAD_CAST value); value = msOWSLookupMetadataWithLanguage(&(lp->metadata), "FO", "keywordlist", validate_language); if(value) msLibXml2GenerateList( xmlNewChild(psRootNode, psNsOws, BAD_CAST "Keywords", NULL), NULL, "Keyword", value, ',' ); /*support DefaultSRS and OtherSRS*/ valueToFree = msOWSGetProjURN(&(map->projection),&(map->web.metadata),"FO",MS_FALSE); if (!valueToFree) valueToFree = msOWSGetProjURN(&(lp->projection), &(lp->metadata), "FO", MS_FALSE); if (valueToFree) { tokens = msStringSplit(valueToFree, ' ', &n); if (tokens && n > 0) { if( nWFSVersion == OWS_1_1_0 ) psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "DefaultSRS", BAD_CAST tokens[0]); else psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "DefaultCRS", BAD_CAST tokens[0]); for (i=1; i<n; i++) { if( nWFSVersion == OWS_1_1_0 ) psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "OtherSRS", BAD_CAST tokens[i]); else psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "OtherCRS", BAD_CAST tokens[i]); } msFreeCharArray(tokens, n); } } else xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Mandatory mapfile parameter: (at least one of) MAP.PROJECTION, LAYER.PROJECTION or wfs/ows_srs metadata was missing in this context.")); free(valueToFree); valueToFree = NULL; /*TODO: adevertize only gml3?*/ psNode = xmlNewNode(NULL, BAD_CAST "OutputFormats"); xmlAddChild(psRootNode, psNode); { char *formats_list = msWFSGetOutputFormatList( map, lp, nWFSVersion ); int iformat, n; char **tokens; n = 0; tokens = msStringSplit(formats_list, ',', &n); for( iformat = 0; iformat < n; iformat++ ) xmlNewChild(psNode, NULL, BAD_CAST "Format", BAD_CAST tokens[iformat] ); msFree( formats_list ); msFreeCharArray( tokens, n ); } /*bbox*/ if (msOWSGetLayerExtent(map, lp, "FO", &ext) == MS_SUCCESS) { /*convert to latlong*/ if (lp->projection.numargs > 0) msOWSProjectToWGS84(&lp->projection, &ext); else msOWSProjectToWGS84(&map->projection, &ext); xmlAddChild(psRootNode, msOWSCommonWGS84BoundingBox( psNsOws, 2, ext.minx, ext.miny, ext.maxx, ext.maxy)); } else { xmlNewChild(psRootNode, psNsOws, BAD_CAST "WGS84BoundingBox", NULL); xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional WGS84BoundingBox could not be established for this layer. Consider setting the EXTENT in the LAYER object, or wfs_extent metadata. Also check that your data exists in the DATA statement")); } value = msOWSLookupMetadata(&(lp->metadata), "FO", "metadataurl_href"); if (value) { if( nWFSVersion >= OWS_2_0_0 ) { psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "MetadataURL", NULL); xmlNewProp(psNode, BAD_CAST "xlink:href", BAD_CAST value); value = msOWSLookupMetadata(&(lp->metadata), "FO", "metadataurl_about"); if( value != NULL ) xmlNewProp(psNode, BAD_CAST "about", BAD_CAST value); } else { psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "MetadataURL", BAD_CAST value); value = msOWSLookupMetadata(&(lp->metadata), "FO", "metadataurl_format"); if (!value) value = msStrdup("text/html"); /* default */ xmlNewProp(psNode, BAD_CAST "format", BAD_CAST value); value = msOWSLookupMetadata(&(lp->metadata), "FO", "metadataurl_type"); if (!value) value = msStrdup("FGDC"); /* default */ xmlNewProp(psNode, BAD_CAST "type", BAD_CAST value); } } return psRootNode; }
static xmlNodePtr msWFSDumpLayer11(mapObj *map, layerObj *lp, xmlNsPtr psNsOws) { rectObj ext; xmlNodePtr psRootNode, psNode; const char *value = NULL; const char *encoding = NULL; char *encoded=NULL; char *valueToFree; char **tokens; int n=0,i=0; encoding = msOWSLookupMetadata(&(map->web.metadata), "FO", "encoding"); if (!encoding) encoding = "ISO-8859-1"; psRootNode = xmlNewNode(NULL, BAD_CAST "FeatureType"); /*if there is an encoding using it on some of the items*/ psNode = msOWSCommonxmlNewChildEncoded(psRootNode, NULL, "Name", lp->name, encoding); if (lp->name && strlen(lp->name) > 0 && (msIsXMLTagValid(lp->name) == MS_FALSE || isdigit(lp->name[0]))) xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: The layer name '%s' might contain spaces or " "invalid characters or may start with a number. This could lead to potential problems")); value = msOWSLookupMetadata(&(lp->metadata), "FO", "title"); if (!value) value =(const char*)lp->name; psNode = msOWSCommonxmlNewChildEncoded(psRootNode, NULL, "Title", value, encoding); value = msOWSLookupMetadata(&(lp->metadata), "FO", "abstract"); if (value) psNode = msOWSCommonxmlNewChildEncoded(psRootNode, NULL, "Abstract", value, encoding); value = msOWSLookupMetadata(&(lp->metadata), "FO", "keywordlist"); if (value) { if (encoding) encoded = msGetEncodedString(value, encoding); else encoded = msGetEncodedString(value, "ISO-8859-1"); msLibXml2GenerateList( xmlNewChild(psRootNode, psNsOws, BAD_CAST "Keywords", NULL), NULL, "Keyword", encoded, ',' ); msFree(encoded); } /*support DefaultSRS and OtherSRS*/ valueToFree = msOWSGetProjURN(&(map->projection),&(map->web.metadata),"FO",MS_FALSE); if (!valueToFree) valueToFree = msOWSGetProjURN(&(lp->projection), &(lp->metadata), "FO", MS_FALSE); if (valueToFree) { tokens = msStringSplit(valueToFree, ' ', &n); if (tokens && n > 0) { psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "DefaultSRS", BAD_CAST tokens[0]); for (i=1; i<n; i++) psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "OtherSRS", BAD_CAST tokens[i]); msFreeCharArray(tokens, n); } } else xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Mandatory mapfile parameter: (at least one of) MAP.PROJECTION, LAYER.PROJECTION or wfs/ows_srs metadata was missing in this context.")); free(valueToFree); valueToFree = NULL; /*TODO: adevertize only gml3?*/ psNode = xmlNewNode(NULL, BAD_CAST "OutputFormats"); xmlAddChild(psRootNode, psNode); { char *formats_list = msWFSGetOutputFormatList( map, lp, "1.1.0" ); int iformat, n; char **tokens; n = 0; tokens = msStringSplit(formats_list, ',', &n); for( iformat = 0; iformat < n; iformat++ ) xmlNewChild(psNode, NULL, BAD_CAST "Format", BAD_CAST tokens[iformat] ); msFree( formats_list ); msFreeCharArray( tokens, n ); } /*bbox*/ if (msOWSGetLayerExtent(map, lp, "FO", &ext) == MS_SUCCESS) { /*convert to latlong*/ if (lp->projection.numargs > 0) { if (!pj_is_latlong(&lp->projection.proj)) msProjectRect(&lp->projection, NULL, &ext); } else if (map->projection.numargs > 0 && !pj_is_latlong(&map->projection.proj)) msProjectRect(&map->projection, NULL, &ext); xmlAddChild(psRootNode, msOWSCommonWGS84BoundingBox( psNsOws, 2, ext.minx, ext.miny, ext.maxx, ext.maxy)); } else { xmlNewChild(psRootNode, psNsOws, BAD_CAST "WGS84BoundingBox", NULL); xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional WGS84BoundingBox could not be established for this layer. Consider setting the EXTENT in the LAYER object, or wfs_extent metadata. Also check that your data exists in the DATA statement")); } value = msOWSLookupMetadata(&(lp->metadata), "FO", "metadataurl_href"); if (value) { psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "MetadataURL", BAD_CAST value); value = msOWSLookupMetadata(&(lp->metadata), "FO", "metadataurl_format"); if (!value) value = msStrdup("text/html"); /* default */ xmlNewProp(psNode, BAD_CAST "format", BAD_CAST value); value = msOWSLookupMetadata(&(lp->metadata), "FO", "metadataurl_type"); if (!value) value = msStrdup("FGDC"); /* default */ xmlNewProp(psNode, BAD_CAST "type", BAD_CAST value); } return psRootNode; }
/********************************************************************** * msBuildWFSLayerGetURL() * * Build a WFS GetFeature URL for a Get Request. * * Returns a reference to a newly allocated string that should be freed * by the caller. **********************************************************************/ static char *msBuildWFSLayerGetURL(mapObj *map, layerObj *lp, rectObj *bbox, wfsParamsObj *psParams) { char *pszURL = NULL, *pszOnlineResource=NULL; const char *pszTmp; char *pszVersion, *pszService, *pszTypename = NULL; int bVersionInConnection = 0, bServiceInConnection = 0; int bTypenameInConnection = 0; size_t bufferSize = 0; if (lp->connectiontype != MS_WFS || lp->connection == NULL) { msSetError(MS_WFSCONNERR, "Call supported only for CONNECTIONTYPE WFS", "msBuildWFSLayerGetURL()"); return NULL; } /* -------------------------------------------------------------------- */ /* Find out request version. Look first for the wfs_version */ /* metedata. If not available try to find out if the CONNECTION */ /* string contains the version. This last test is done for */ /* backward compatiblity but is depericated. */ /* -------------------------------------------------------------------- */ pszVersion = psParams->pszVersion; if (!pszVersion) { if ((pszTmp = strstr(lp->connection, "VERSION=")) == NULL && (pszTmp = strstr(lp->connection, "version=")) == NULL ) { msSetError(MS_WFSCONNERR, "Metadata wfs_version must be set in the layer", "msBuildWFSLayerGetURL()"); return NULL; } pszVersion = strchr(pszTmp, '=')+1; bVersionInConnection = 1; } if (strncmp(pszVersion, "0.0.14", 6) != 0 && strncmp(pszVersion, "1.0.0", 5) != 0 && strncmp(pszVersion, "1.1", 3) != 0) { msSetError(MS_WFSCONNERR, "MapServer supports only WFS 1.0.0 or 0.0.14 (please verify the version metadata wfs_version).", "msBuildWFSLayerGetURL()"); return NULL; } /* -------------------------------------------------------------------- */ /* Find out the service. It is always set to WFS in function */ /* msBuildRequestParms (check Bug 1302 for details). */ /* -------------------------------------------------------------------- */ pszService = psParams->pszService; /* -------------------------------------------------------------------- */ /* Find out the typename. Look first for the wfs_tyename */ /* metadata. If not available try to find out if the CONNECTION */ /* string contains it. This last test is done for */ /* backward compatiblity but is depericated. */ /* -------------------------------------------------------------------- */ pszTypename = psParams->pszTypeName; if (!pszTypename) { if ((pszTmp = strstr(lp->connection, "TYPENAME=")) == NULL && (pszTmp = strstr(lp->connection, "typename=")) == NULL ) { msSetError(MS_WFSCONNERR, "Metadata wfs_typename must be set in the layer", "msBuildWFSLayerGetURL()"); return NULL; } bTypenameInConnection = 1; } /* -------------------------------------------------------------------- * Build the request URL. * At this point we set only the following parameters for GetFeature: * REQUEST * BBOX * VERSION * SERVICE * TYPENAME * FILTER * MAXFEATURES * * For backward compatiblity the user could also have in the connection * string the following parameters (but it is depricated): * VERSION * SERVICE * TYPENAME * -------------------------------------------------------------------- */ /* Make sure we have a big enough buffer for the URL */ bufferSize = strlen(lp->connection)+1024; pszURL = (char *)malloc(bufferSize); MS_CHECK_ALLOC(pszURL, bufferSize, NULL); /* __TODO__ We have to urlencode each value... especially the BBOX values */ /* because if they end up in exponent format (123e+06) the + will be seen */ /* as a space by the remote server. */ /* -------------------------------------------------------------------- */ /* build the URL, */ /* -------------------------------------------------------------------- */ /* make sure connection ends with "&" or "?" */ pszOnlineResource = msOWSTerminateOnlineResource(lp->connection); snprintf(pszURL, bufferSize, "%s", pszOnlineResource); msFree(pszOnlineResource); /* REQUEST */ snprintf(pszURL + strlen(pszURL), bufferSize-strlen(pszURL), "&REQUEST=GetFeature"); /* VERSION */ if (!bVersionInConnection) snprintf(pszURL + strlen(pszURL), bufferSize-strlen(pszURL), "&VERSION=%s", pszVersion); /* SERVICE */ if (!bServiceInConnection) snprintf(pszURL + strlen(pszURL), bufferSize-strlen(pszURL), "&SERVICE=%s", pszService); /* TYPENAME */ if (!bTypenameInConnection) snprintf(pszURL + strlen(pszURL), bufferSize-strlen(pszURL), "&TYPENAME=%s", pszTypename); /* -------------------------------------------------------------------- */ /* If the filter parameter is given in the wfs_filter metadata, */ /* we use it and do not send the BBOX paramter as they are */ /* mutually exclusive. */ /* -------------------------------------------------------------------- */ if (psParams->pszFilter) { char *encoded_filter = msEncodeUrl(psParams->pszFilter); snprintf(pszURL + strlen(pszURL), bufferSize-strlen(pszURL), "&FILTER=%s",encoded_filter); free(encoded_filter); } else { /* * take care about the axis order for WFS 1.1 */ char *projUrn; char *projEpsg; projUrn = msOWSGetProjURN(&(lp->projection), &(lp->metadata), "FO", 1); msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "FO", 1, &projEpsg); /* * WFS 1.1 supports including the SRS in the BBOX parameter, should * respect axis order in the BBOX and has a separate SRSNAME parameter for * the desired result SRS. * WFS 1.0 is always easting, northing, doesn't include the SRS as part of * the BBOX parameter and has no SRSNAME parameter: if we don't have a * URN then fallback to WFS 1.0 style */ if ((strncmp(pszVersion, "1.1", 3) == 0) && projUrn) { if (projEpsg && (strncmp(projEpsg, "EPSG:", 5) == 0) && msIsAxisInverted(atoi(projEpsg + 5))) { snprintf(pszURL + strlen(pszURL), bufferSize - strlen(pszURL), "&BBOX=%.15g,%.15g,%.15g,%.15g,%s&SRSNAME=%s", bbox->miny, bbox->minx, bbox->maxy, bbox->maxx, projUrn, projUrn); } else { snprintf(pszURL + strlen(pszURL), bufferSize - strlen(pszURL), "&BBOX=%.15g,%.15g,%.15g,%.15g,%s&SRSNAME=%s", bbox->minx, bbox->miny, bbox->maxy, bbox->maxy, projUrn, projUrn); } } else { snprintf(pszURL + strlen(pszURL), bufferSize - strlen(pszURL), "&BBOX=%.15g,%.15g,%.15g,%.15g", bbox->minx, bbox->miny, bbox->maxx, bbox->maxy); } msFree(projUrn); msFree(projEpsg); } if (psParams->nMaxFeatures > 0) snprintf(pszURL + strlen(pszURL), bufferSize-strlen(pszURL), "&MAXFEATURES=%d", psParams->nMaxFeatures); return pszURL; }