MapGuide RFC 163 - GeoJSON support for WFS/WMS
This page contains a change request (RFC) for the MapGuide Open Source project. More MapGuide RFCs can be found on the RFCs page.
Status
RFC Template Version | (1.0) |
Submission Date | 14 Nov 2017 |
Last Modified | 10 Dec 2017 |
Author | Jackie Ng |
RFC Status | adopted |
Implementation Status | implemented |
Proposed Milestone | 4.0 |
Assigned PSC guide(s) | (when determined) |
Voting History | (vote date) |
+1 | Jackie,Gordon,Haris |
+0 | |
-0 | |
-1 | |
no vote |
Overview
This RFC proposes to add support for GeoJSON as an output format for:
- WFS
GetFeatures
- WMS
GetFeatureInfo
Along with required infrastructure changes needed to support the above 2 cases.
Motivation
WFS/WMS support in MapGuide is very bare-bones. The usability of WFS/WMS services can be greatly enhanced with support for GeoJSON as an output format, especially for WMS GetFeatureInfo
, where a GeoJSON response can function as a client-side feature selection overlay with geometry data present.
Proposed Solution
This RFC is completed and ready to merge from the ogc sandbox. Upon adoption of the RFC, the branch will be merged into trunk. The solution in detail is described below.
application/json
will be advertised as a supported output format for WFS GetFeatures
and WMS GetFeatureInfo
GeoJSON Support for WFS GetFeatures
The current GetWfsFeature
method of MgFeatureService
is the method that WFS GetFeatures
ultimately calls to return data for feature data in a WFS GetFeatures
response.
However this method is not re-usable for implementing alternate output formats for WFS GetFeatures
because the API itself is GML-centric:
- Various input parameters have GML-isms
- The return value is an
MgByteReader
with GML content
To support GeoJSON output for WFS GetFeatures
, we need a method that gives us the underlying feature reader primitive, which we can then convert to our desired output format of choice in the Web Tier.
We'll add a new GetWfsReader
method for this very purpose:
class MG_PLATFORMBASE_API MgFeatureService : public MgService { PUBLISHED_API: //////////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief /// Retrieves feature information based on the supplied criteria. /// /// \note1 /// /// <!-- Syntax in .Net, Java, and PHP --> /// \htmlinclude DotNetSyntaxTop.html /// virtual MgFeatureReader GetWfsReader(MgResourceIdentifier featureSourceId, string featureClass, MgStringCollection requiredProperties, string srs, string filter, int maxFeatures, string outputFormat, string sortCriteria); /// \htmlinclude SyntaxBottom.html /// \htmlinclude JavaSyntaxTop.html /// virtual MgFeatureReader GetWfsReader(MgResourceIdentifier featureSourceId, string featureClass, MgStringCollection requiredProperties, string srs, string filter, int maxFeatures, string outputFormat, string sortCriteria); /// \htmlinclude SyntaxBottom.html /// \htmlinclude PHPSyntaxTop.html /// virtual MgFeatureReader GetWfsReader(MgResourceIdentifier featureSourceId, string featureClass, MgStringCollection requiredProperties, string srs, string filter, int maxFeatures, string outputFormat, string sortCriteria); /// \htmlinclude SyntaxBottom.html /// /// \param featureSourceId (MgResourceIdentifier) /// The resource identifier defining the /// location of the feature source in /// the repository. /// \param featureClass (String/string) /// The feature class containing the features to retrieve. /// \param requiredProperties (MgStringCollection) /// The collection of properties to retrieve for each feature. If the /// collection is null or empty, all properties will be retrieved. /// \param srs (String/string) /// The spatial reference system in which to return feature geometries /// \param filter (String/string) /// An XML string containing the definition for an OGC filter /// \param sortCriteria (String/string) /// A string identifying the sort criteria /// /// \remarks /// The purpose of this method, as opposed to GetWfsFeature is to return the base reader using the same input parameters /// allowing for the caller to determine the desired output format and the desired content transformations required from /// the reader. /// /// The main use case for this method is for providing the base feature reader for outputting WFS GetFeature responses in /// formats other than GML /// /// \return /// Returns an MgByteReader containing the requested feature information. /// /// \exception MgInvalidArgumentException /// /// \since 3.3 virtual MgFeatureReader* GetWfsReader(MgResourceIdentifier* featureSourceId, CREFSTRING featureClass, MgStringCollection* requiredProperties, CREFSTRING srs, CREFSTRING filter, CREFSTRING sortCriteria) = 0; };
From the Web Tier, the MgHttpWfsGetFeature
implementation will call this method instead of MgFeatureService::GetWfsFeature
if the INFO_FORMAT
parameter passed in is application/json
. The returned reader is then housed in our existing GeoJSON output adapter (introduced in MapGuideRfc158) to convert the feature reader data to GeoJSON.
GeoJSON Support for WMS GetFeatureInfo
For WMS GetFeatureInfo
, there are cases where being able to return geometry data is useful. However there is only one format where the geometry data would be consumable: GeoJSON.
To support GeoJSON output, we must first support the ability to output geometry data in a WMS GetFeatureInfo
. The QueryFeatureProperties
method of MgRenderingService
is the method that provides this data. We will add a new internal overload that allows including geometry data as MgGeometryProperty
instances for each MgPropertyCollection
of the returned MgBatchPropertyCollection
class MG_MAPGUIDE_API MgRenderingService : public MgService { INTERNAL_API: ///////////////////////////////////////////////////////////////// /// \brief /// The QueryFeatureProperties operation identifies those features that /// meet the specified spatial selection criteria. This operation /// is used to implement WMS feature info and returns property values /// for all features which match the spatial query /// /// \param map /// Input /// map object containing current state of map. /// \param layerNames /// Input /// Active layer names for which to query features /// \param filterGeometry /// Input /// geometry object specifying the selection area /// \param selectionVariant /// Input /// selection criterion - integer value corresponding to one of /// the MgFeatureSpatialOperations values /// \param featureFilter /// Input /// an XML selection string containing the required feature IDs /// \param maxFeatures /// Input /// the maximum number of features to return /// \param layerAttributeFilter /// Input /// bitmask values - 1=Visible, 2=Selectable, 4=HasTooltips /// \param bIncludeFeatureBBOX /// Input /// Indicates whether a bounding box should be included. If true, bounding box is recorded as a special property named _MgFeatureBoundingBox /// \param bIncludeGeometry /// Input /// Indicates whether a bounding box should be included. If true, bounding box is recorded as a special property named _MgFeatureBoundingBox /// /// \return /// An MgSelection instance identifying the features that meet the /// selection criteria. Returns null if no features are identified. /// virtual MgBatchPropertyCollection* QueryFeatureProperties( MgMap* map, MgStringCollection* layerNames, MgGeometry* filterGeometry, INT32 selectionVariant, CREFSTRING featureFilter, INT32 maxFeatures, INT32 layerAttributeFilter, bool bIncludeFeatureBBOX, bool bIncludeGeometry) = 0; };
The geometry data will be stored as a MgGeometryProperty
instance within each child MgPropertyCollection
of the MgBatchPropertyCollection
as a special property named _MgGeometry
The MgHttpWmsGetFeatureInfo
class in the HttpHandler
project will be modified to call this new overload.
New OGC XML template engine directives and definitions
Now that we have the infrastructure to return geometry data, we'll add new directives and definitions in the OGC XML templating engine that can detect and output this geometry data.
EnumFeatureGeometries
- Enumerates all geometry properties of the current feature. Will only enumerate once at most for each feature if geometry data is present.FeatureInfo.IsLast
- Defines if the current feature is the last one in the iteration. This is needed for GeoJSON so we know when it is needed to insert the delimiting,
between GeoJSON features.FeatureProperty.IsLast
- Defines if the current property is the last one in the iteration. This is needed for GeoJSON so we know when it is needed to insert the delimiting,
between GeoJSON properties.FeatureGeometry.Value
- Defines the geometry value. The source of the definition (A newMgWmsFeatureGeometry
class) will output a GeoJSON geometry fragment if theINFO_FORMAT
isapplication/json
. Otherwise it outputs the geometry as WKT text.
To illustrate how these directives and definitions are used. These are the additions to the WMS XML template (all versions) to support GeoJSON output for WMS GetFeatureInfo
<!-- WMS GetFeatureInfo GeoJSON response body --> <Response request="GetFeatureInfo" content-type="application/json">{ "type": "FeatureCollection", "features": [<?EnumFeatureInfo using="&FeatureInfo.json;" ?>] }</Response> <!-- Definition for a GeoJSON feature --> <Define item="FeatureInfo.json">{ "type": "Feature", "properties": {<?EnumFeatureProperties using="&FeatureProperty.json;" ?>} <?EnumFeatureGeometries using="&FeatureGeometry.json;" ?> }<?If l="&FeatureInfo.IsLast" op="eq" r="0"?>,<?Endif?></Define> <!-- Definition for a GeoJSON property --> <Define item="FeatureProperty.json">"&FeatureProperty.Name;": "&FeatureProperty.Value;"<?If l="&FeatureProperty.IsLast" op="eq" r="0"?>,<?Endif?></Define> <!-- Definition for a GeoJSON geometry --> <Define item="FeatureGeometry.json">,"geometry": &FeatureGeometry.Value;</Define>
To ensure formats other than GeoJSON can output geometry data, GetFeatureInfo
response templates for other templates will be modified as such:
text/plain
- Geometry data is output as WKT on another line itemtext/html
- Geometry data is output as WKT in its ownGeometry
table cell valuetext/xml
- Geometry data is output as WKT in its own<Property>
element namedGeometry
Configurable Geometry output
Although we now enable geometry output for WMS GetFeatureInfo
with the RFC, it may not be desirable to have this enabled unconditionally.
To control whether to emit geometry data in a WMS GetFeatureInfo
response, we define a new _EnableGeometry
simple metadata property in the resource header XML of a Layer Definition. If set to 1
in a layer's resource header XML, the WMS GetFeatureInfo
requests against this layer will include geometry data in its response, otherwise geometry data is omitted.
The _EnableGeometry
property has no effect if the _Queryable
property is not set to 1
(ie. The layer is not published for WMS consumption).
As this is a new metadata property, this has the effect of geometry output for WMS GetFeatureInfo
being opt-in. By default, no geometry data is output unless _EnableGeometry
is defined in the layer resource header with a value of 1
(in addition to _Queryable
being set to 1
)
Implications
These are new output formats advertised in WFS and WMS capabilities. Existing output formats are not affected.
Geometry output is opt-in, so existing WMS GetFeatureInfo
response will look as they are until the user *chooses* to enable geometry output.
Test Plan
Verify GeoJSON output is present for GetFeature
for all supported WFS versions.
Verify GeoJSON output is present for GetFeatureInfo
for all supported WMS versions.
Verify geometry data is output only for WMS published layer where _EnableGeometry
is set to 1
Funding / Resources
Community