Skip to content

Commit

Permalink
WFS: make WFS 2.0 GetFeature on multiple layers compliant with 11.3.3…
Browse files Browse the repository at this point in the history
….5 (one FeatureCollection for each layer as a wfs:member of the main FeatureCollection)
  • Loading branch information
rouault committed Nov 20, 2013
1 parent a95dc04 commit 9edae04
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 38 deletions.
76 changes: 46 additions & 30 deletions mapgml.c
Original file line number Diff line number Diff line change
Expand Up @@ -1407,43 +1407,21 @@ int msGMLWriteQuery(mapObj *map, char *filename, const char *namespaces)
#endif
}

/*
** msGMLWriteWFSQuery()
**
** Similar to msGMLWriteQuery() but tuned for use with WFS
*/
int msGMLWriteWFSQuery(mapObj *map, FILE *stream, const char *default_namespace_prefix,
OWSGMLVersion outputformat, int nWFSVersion, int bUseURN,
int bGetPropertyValueRequest)
{
#ifdef USE_WFS_SVR
int status;
int i,j,k;
layerObj *lp=NULL;
shapeObj shape;
void msGMLWriteWFSBounds(mapObj *map, FILE *stream, const char *tab,
OWSGMLVersion outputformat, int nWFSVersion, int bUseURN)
{
rectObj resultBounds = {-1.0,-1.0,-1.0,-1.0};

gmlGroupListObj *groupList=NULL;
gmlItemListObj *itemList=NULL;
gmlConstantListObj *constantList=NULL;
gmlGeometryListObj *geometryList=NULL;
gmlItemObj *item=NULL;
gmlConstantObj *constant=NULL;

const char *namespace_prefix=NULL;
int bSwapAxis = 0;
double tmp;

msInitShape(&shape);

/*add a check to see if the map projection is set to be north-east*/
bSwapAxis = msIsAxisInvertedProj(&(map->projection));
int bSwapAxis = msIsAxisInvertedProj(&(map->projection));

/* Need to start with BBOX of the whole resultset */
if (!bGetPropertyValueRequest &&
msGetQueryResultBounds(map, &resultBounds) > 0) {
if (msGetQueryResultBounds(map, &resultBounds) > 0) {
char* srs = NULL;
if (bSwapAxis) {
double tmp;

tmp = resultBounds.minx;
resultBounds.minx = resultBounds.miny;
resultBounds.miny = tmp;
Expand All @@ -1469,10 +1447,48 @@ int msGMLWriteWFSQuery(mapObj *map, FILE *stream, const char *default_namespace_
srs = msStrdup(constsrs);
}

gmlWriteBounds(stream, outputformat, &resultBounds, srs, " ",
gmlWriteBounds(stream, outputformat, &resultBounds, srs, tab,
(nWFSVersion == OWS_2_0_0) ? "wfs" : "gml");
msFree(srs);
}
}

#endif

/*
** msGMLWriteWFSQuery()
**
** Similar to msGMLWriteQuery() but tuned for use with WFS
*/
int msGMLWriteWFSQuery(mapObj *map, FILE *stream, const char *default_namespace_prefix,
OWSGMLVersion outputformat, int nWFSVersion, int bUseURN,
int bGetPropertyValueRequest)
{
#ifdef USE_WFS_SVR
int status;
int i,j,k;
layerObj *lp=NULL;
shapeObj shape;

gmlGroupListObj *groupList=NULL;
gmlItemListObj *itemList=NULL;
gmlConstantListObj *constantList=NULL;
gmlGeometryListObj *geometryList=NULL;
gmlItemObj *item=NULL;
gmlConstantObj *constant=NULL;

const char *namespace_prefix=NULL;
int bSwapAxis;

msInitShape(&shape);

/*add a check to see if the map projection is set to be north-east*/
bSwapAxis = msIsAxisInvertedProj(&(map->projection));

/* Need to start with BBOX of the whole resultset */
if (!bGetPropertyValueRequest) {
msGMLWriteWFSBounds(map, stream, " ", outputformat, nWFSVersion, bUseURN);
}
/* step through the layers looking for query results */
for(i=0; i<map->numlayers; i++) {

Expand Down
4 changes: 4 additions & 0 deletions mapows.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,10 @@ MS_DLL_EXPORT int msGMLWriteQuery(mapObj *map, char *filename, const char *names


#ifdef USE_WFS_SVR

void msGMLWriteWFSBounds(mapObj *map, FILE *stream, const char *tab,
OWSGMLVersion outputformat, int nWFSVersion, int bUseURN);

MS_DLL_EXPORT int msGMLWriteWFSQuery(mapObj *map, FILE *stream, const char *wfs_namespace,
OWSGMLVersion outputformat, int nWFSVersion, int bUseURN,
int bGetPropertyValueRequest);
Expand Down
90 changes: 83 additions & 7 deletions mapwfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -3726,7 +3726,9 @@ int msWFSGetFeature(mapObj *map, wfsParamsObj *paramsObj, cgiRequestObj *req,
if( psFormat == NULL ) {
if(maxfeatures != 0 && iResultTypeHits == 0)
{
layerObj* lp;
int i;
int bWFS2MultipleFeatureCollection = MS_FALSE;

/* Would make sense for WFS 1.1.0 too ! See #3576 */
int bUseURN = (nWFSVersion == OWS_2_0_0);
Expand All @@ -3738,7 +3740,7 @@ int msWFSGetFeature(mapObj *map, wfsParamsObj *paramsObj, cgiRequestObj *req,

for(i=0;i<map->numlayers;i++)
{
layerObj* lp = GET_LAYER(map, i);
lp = GET_LAYER(map, i);
if( papszGMLGroups[i] )
msInsertHashTable(&(lp->metadata), "GML_GROUPS", papszGMLGroups[i]);
if( papszGMLIncludeItems[i] )
Expand All @@ -3747,12 +3749,86 @@ int msWFSGetFeature(mapObj *map, wfsParamsObj *paramsObj, cgiRequestObj *req,
msInsertHashTable(&(lp->metadata), "GML_GEOMETRIES", papszGMLGeometries[i]);
}

status = msGMLWriteWFSQuery(map, stdout,
gmlinfo.user_namespace_prefix,
outputformat,
nWFSVersion,
bUseURN,
MS_FALSE);
/* For WFS 2.0, when we request several types, we must present each type */
/* in its own FeatureCollection (§ 11.3.3.5 ) */
if( nWFSVersion >= OWS_2_0_0 && iResultTypeHits != 1 )
{
int nLayersWithFeatures = 0;
for(i=0; i<map->numlayers; i++) {
lp = GET_LAYER(map, i);
if(lp->resultcache && lp->resultcache->numresults > 0)
nLayersWithFeatures ++;
}
if( nLayersWithFeatures > 1 )
{
char timestring[100];
resultCacheObj** saveResultCache = (resultCacheObj** )
msSmallMalloc( map->numlayers * sizeof(resultCacheObj*));
int iLastNonEmptyLayer = -1;

msWFSGetFeature_GetTimeStamp(timestring, sizeof(timestring));

/* Emit global bounds */
msGMLWriteWFSBounds(map, stdout, " ", outputformat, nWFSVersion, bUseURN);

/* Save the result cache that contains the features that we want to */
/* emit in the response */
for(i=0; i<map->numlayers; i++) {
lp = GET_LAYER(map, i);
saveResultCache[i] = lp->resultcache;
if( lp->resultcache && lp->resultcache->numresults > 0) {
iLastNonEmptyLayer = i;
}
lp->resultcache = NULL;
}

/* Just dump one layer at a time */
for(i=0;i<map->numlayers;i++) {
lp = GET_LAYER(map, i);
lp->resultcache = saveResultCache[i];
if( lp->resultcache && lp->resultcache->numresults > 0) {
msIO_fprintf(stdout, " <wfs:member>\n");
msIO_fprintf(stdout, " <wfs:FeatureCollection timeStamp=\"%s\" numberMatched=\"", timestring);
if( i < iLastNonEmptyLayer || nMatchingFeatures >= 0 )
msIO_fprintf(stdout, "%d", lp->resultcache->numresults );
else
msIO_fprintf(stdout, "unknown" );
msIO_fprintf(stdout, "\" numberReturned=\"%d\">\n", lp->resultcache->numresults );

msGMLWriteWFSQuery(map, stdout,
gmlinfo.user_namespace_prefix,
outputformat,
nWFSVersion,
bUseURN,
MS_FALSE);
msIO_fprintf(stdout, " </wfs:FeatureCollection>\n");
msIO_fprintf(stdout, " </wfs:member>\n");
}
lp->resultcache = NULL;
}

/* Restore for later cleanup */
for(i=0; i<map->numlayers; i++) {
lp = GET_LAYER(map, i);
lp->resultcache = saveResultCache[i];
}
msFree(saveResultCache);

bWFS2MultipleFeatureCollection = MS_TRUE;
}
}

if( !bWFS2MultipleFeatureCollection )
{
msGMLWriteWFSQuery(map, stdout,
gmlinfo.user_namespace_prefix,
outputformat,
nWFSVersion,
bUseURN,
MS_FALSE);
}

status = MS_SUCCESS;
}
} else {
mapservObj *mapserv = msAllocMapServObj();
Expand Down
2 changes: 1 addition & 1 deletion msautotest
Submodule msautotest updated from 3207dc to f45268

0 comments on commit 9edae04

Please sign in to comment.