Skip to content

Commit 2b66c35

Browse files
committed
GeoJSON output: automatically add a numberMatched property for WFS 2.0 GetFeature responses when wfs_compute_number_matched=true
1 parent f42d7d1 commit 2b66c35

File tree

5 files changed

+105
-3
lines changed

5 files changed

+105
-3
lines changed

mapogroutput.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -699,16 +699,23 @@ int msOGRWriteFromQuery( mapObj *map, outputFormatObj *format, int sendheaders )
699699
int iLayer, i;
700700
int bDataSourceNameIsRequestDir = FALSE;
701701
int bUseFeatureId = MS_FALSE;
702+
const char* pszMatchingFeatures;
703+
int nMatchingFeatures = -1;
704+
const char* pszFormatName = format->driver+4;
705+
706+
pszMatchingFeatures = msGetOutputFormatOption(format, "_matching_features_", "");
707+
if( pszMatchingFeatures[0] != '\0' )
708+
nMatchingFeatures = atoi(pszMatchingFeatures);
702709

703710
/* -------------------------------------------------------------------- */
704711
/* Fetch the output format driver. */
705712
/* -------------------------------------------------------------------- */
706713
msOGRInitialize();
707714

708-
hDriver = OGRGetDriverByName( format->driver+4 );
715+
hDriver = OGRGetDriverByName( pszFormatName );
709716
if( hDriver == NULL ) {
710717
msSetError( MS_MISCERR, "No OGR driver named `%s' available.",
711-
"msOGRWriteFromQuery()", format->driver+4 );
718+
"msOGRWriteFromQuery()", pszFormatName );
712719
return MS_FAILURE;
713720
}
714721

@@ -723,6 +730,29 @@ int msOGRWriteFromQuery( mapObj *map, outputFormatObj *format, int sendheaders )
723730
ds_options = CSLAddString( ds_options,
724731
format->formatoptions[i] + 5 );
725732
}
733+
if( EQUAL(pszFormatName, "GeoJSON") && nMatchingFeatures >= 0 )
734+
{
735+
const char* pszNativeData =
736+
CSLFetchNameValueDef(layer_options, "NATIVE_DATA", "{}");
737+
if( pszNativeData[strlen(pszNativeData)-1] == '}' )
738+
{
739+
char szTemp[32];
740+
char* pszTemplate = msSmallMalloc(strlen(pszNativeData) + 32);
741+
strcpy(pszTemplate, pszNativeData);
742+
pszTemplate[strlen(pszTemplate)-1] = 0;
743+
if( strlen(pszNativeData) > 2 )
744+
strcat(pszTemplate, ",");
745+
sprintf(szTemp, "\"numberMatched\":%d}", nMatchingFeatures);
746+
strcat(pszTemplate, szTemp);
747+
layer_options = CSLSetNameValue(layer_options,
748+
"NATIVE_MEDIA_TYPE",
749+
"application/vnd.geo+json");
750+
layer_options = CSLSetNameValue(layer_options,
751+
"NATIVE_DATA",
752+
pszTemplate);
753+
msFree(pszTemplate);
754+
}
755+
}
726756
if(!strcasecmp("true",msGetOutputFormatOption(format,"USE_FEATUREID","false"))) {
727757
bUseFeatureId = MS_TRUE;
728758
}

mapwfs.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3976,6 +3976,17 @@ int msWFSGetFeature(mapObj *map, wfsParamsObj *paramsObj, cgiRequestObj *req,
39763976
mapserv->request = req;
39773977
map->querymap.status = MS_FALSE;
39783978

3979+
if( nMatchingFeatures >= 0 )
3980+
{
3981+
char szMatchingFeatures[12];
3982+
sprintf(szMatchingFeatures, "%d", nMatchingFeatures);
3983+
msSetOutputFormatOption( psFormat, "_matching_features_",
3984+
szMatchingFeatures);
3985+
}
3986+
else
3987+
{
3988+
msSetOutputFormatOption( psFormat, "_matching_features_", "");
3989+
}
39793990
status = msReturnTemplateQuery( mapserv, psFormat->name, NULL );
39803991

39813992
mapserv->request = NULL;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Content-Type: application/json; subtype=geojson; charset=utf-8
2+
3+
{
4+
"type": "FeatureCollection",
5+
"numberMatched": 28,
6+
"name": "popplace_fid",
7+
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3978" } },
8+
"features": [
9+
{ "type": "Feature", "id": 0, "properties": { "UNIQUE_KEY": "BACMK", "NAME": "\"Tignish", "CAPITAL": 0, "POP_CLASS": 1 }, "geometry": { "type": "Point", "coordinates": [ 2281604.25, 340848.9375 ] } },
10+
{ "type": "Feature", "id": 1215011, "properties": { "UNIQUE_KEY": "CAGYX", "NAME": "'Cheticamp", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2503805.5, 427872.65625 ] } },
11+
{ "type": "Feature", "id": 1209036, "properties": { "UNIQUE_KEY": "CBIKA", "NAME": "Sheet Harbour", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2499190.0, 194088.23438 ] } },
12+
{ "type": "Feature", "id": 1101036, "properties": { "UNIQUE_KEY": "BACII", "NAME": "'Souris'", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2434957.0, 347013.59375 ] } },
13+
{ "type": "Feature", "id": 1213006, "properties": { "UNIQUE_KEY": "CAGBW", "NAME": "\"Canso\"", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2578914.25, 292073.09375 ] } },
14+
{ "type": "Feature", "id": 1215002, "properties": { "UNIQUE_KEY": "CBELL", "NAME": "Port Hawkesbury", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2536072.75, 311524.96875 ] } },
15+
{ "type": "Feature", "id": 1214002, "properties": { "UNIQUE_KEY": "CAATB", "NAME": "Antigonish", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2494520.0, 285855.40625 ] } },
16+
{ "type": "Feature", "id": 1211008, "properties": { "UNIQUE_KEY": "CBKDH", "NAME": "Springhill", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2348711.75, 204294.0625 ] } },
17+
{ "type": "Feature", "id": 1208002, "properties": { "UNIQUE_KEY": "CBPAK", "NAME": "\"Wind\"sor", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2377598.0, 135734.70312 ] } },
18+
{ "type": "Feature", "id": 1206006, "properties": { "UNIQUE_KEY": "CAWAZ", "NAME": "Lunenburg", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2398677.25, 70608.14062 ] } }
19+
]
20+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Content-Type: application/json; subtype=geojson; charset=utf-8
2+
3+
{
4+
"type": "FeatureCollection",
5+
"foo": "bar",
6+
"numberMatched": 28,
7+
"name": "popplace_fid",
8+
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3978" } },
9+
"features": [
10+
{ "type": "Feature", "id": 0, "properties": { "UNIQUE_KEY": "BACMK", "NAME": "\"Tignish", "CAPITAL": 0, "POP_CLASS": 1 }, "geometry": { "type": "Point", "coordinates": [ 2281604.25, 340848.9375 ] } },
11+
{ "type": "Feature", "id": 1215011, "properties": { "UNIQUE_KEY": "CAGYX", "NAME": "'Cheticamp", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2503805.5, 427872.65625 ] } },
12+
{ "type": "Feature", "id": 1209036, "properties": { "UNIQUE_KEY": "CBIKA", "NAME": "Sheet Harbour", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2499190.0, 194088.23438 ] } },
13+
{ "type": "Feature", "id": 1101036, "properties": { "UNIQUE_KEY": "BACII", "NAME": "'Souris'", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2434957.0, 347013.59375 ] } },
14+
{ "type": "Feature", "id": 1213006, "properties": { "UNIQUE_KEY": "CAGBW", "NAME": "\"Canso\"", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2578914.25, 292073.09375 ] } },
15+
{ "type": "Feature", "id": 1215002, "properties": { "UNIQUE_KEY": "CBELL", "NAME": "Port Hawkesbury", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2536072.75, 311524.96875 ] } },
16+
{ "type": "Feature", "id": 1214002, "properties": { "UNIQUE_KEY": "CAATB", "NAME": "Antigonish", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2494520.0, 285855.40625 ] } },
17+
{ "type": "Feature", "id": 1211008, "properties": { "UNIQUE_KEY": "CBKDH", "NAME": "Springhill", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2348711.75, 204294.0625 ] } },
18+
{ "type": "Feature", "id": 1208002, "properties": { "UNIQUE_KEY": "CBPAK", "NAME": "\"Wind\"sor", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2377598.0, 135734.70312 ] } },
19+
{ "type": "Feature", "id": 1206006, "properties": { "UNIQUE_KEY": "CAWAZ", "NAME": "Lunenburg", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2398677.25, 70608.14062 ] } }
20+
]
21+
}

msautotest/wxs/wfs_ogr_geojson.map

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
#
66
# Test OGR geojson output.
77
# RUN_PARMS: wfsogr10_geojson.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=popplace_fid&OUTPUTFORMAT=geojson" > [RESULT]
8+
#
9+
# RUN_PARMS: wfsogr20_geojson.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=popplace_fid&OUTPUTFORMAT=geojson&COUNT=10" > [RESULT]
10+
#
11+
# RUN_PARMS: wfsogr20_geojson_with_predefine_native_data.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=popplace_fid&OUTPUTFORMAT=geojson_with_predefined_native_data&COUNT=10" > [RESULT]
12+
813
MAP
914

1015
NAME WFS_OGROUT_TEST
@@ -24,6 +29,20 @@ OUTPUTFORMAT
2429
FORMATOPTION "USE_FEATUREID=true"
2530
FORMATOPTION "LCO:COORDINATE_PRECISION=5"
2631
END
32+
33+
34+
OUTPUTFORMAT
35+
NAME "geojson_with_predefined_native_data"
36+
DRIVER "OGR/GEOJSON"
37+
MIMETYPE "application/json; subtype=geojson; charset=utf-8"
38+
FORMATOPTION "STORAGE=stream"
39+
FORMATOPTION "FORM=SIMPLE"
40+
FORMATOPTION "USE_FEATUREID=true"
41+
FORMATOPTION "LCO:COORDINATE_PRECISION=5"
42+
FORMATOPTION "LCO:NATIVE_MEDIA_TYPE=application/vnd.geo+json"
43+
FORMATOPTION "LCO:NATIVE_DATA={\"foo\":\"bar\"}"
44+
END
45+
2746
#
2847
WEB
2948

@@ -60,6 +79,7 @@ WEB
6079
"ows_role" "staff"
6180
"wms_feature_info_mime_type" "text/csv"
6281
"ows_enable_request" "*"
82+
"wfs_compute_number_matched" "true"
6383
END
6484
END
6585

@@ -78,7 +98,7 @@ LAYER
7898
"wfs_title" "popplace"
7999
"wfs_description" "populated places"
80100
"wfs_featureid" "SGC_CODE"
81-
"wfs_getfeature_formatlist" "geojson"
101+
"wfs_getfeature_formatlist" "geojson,geojson_with_predefined_native_data"
82102
"gml_include_items" "NAME,UNIQUE_KEY,CAPITAL,POP_RANGE"
83103
"gml_POP_RANGE_alias" "POP_CLASS"
84104
"gml_types" "auto"

0 commit comments

Comments
 (0)