wiki:MapGuideRfc163

Version 1 (modified by jng, 7 years ago) ( diff )

--

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 Date14 Nov 2017
Last Modified14 Nov 2017
AuthorJackie Ng
RFC Statusdraft
Implementation Statuspending
Proposed Milestone3.3
Assigned PSC guide(s)(when determined)
Voting History(vote date)
+1
+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

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 new MgWmsFeatureGeometry class) will output a GeoJSON geometry fragment if the INFO_FORMAT is application/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 item
  • text/html - Geometry data is output as WKT in its own Geometry table cell value
  • text/xml - Geometry data is output as WKT in its own <Property> element named Geometry

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

Note: See TracWiki for help on using the wiki.