[mapguide-commits] r8833 - in sandbox/jng/clean_json: Common/PlatformBase Common/PlatformBase/Services Web/src/DotNetUnmanagedApi/PlatformBase Web/src/HttpHandler Web/src/MapGuideApi

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Wed Nov 18 06:34:10 PST 2015


Author: jng
Date: 2015-11-18 06:34:10 -0800 (Wed, 18 Nov 2015)
New Revision: 8833

Added:
   sandbox/jng/clean_json/Common/PlatformBase/Services/GeoJsonWriter.cpp
   sandbox/jng/clean_json/Common/PlatformBase/Services/GeoJsonWriter.h
Modified:
   sandbox/jng/clean_json/Common/PlatformBase/PlatformBase.h
   sandbox/jng/clean_json/Common/PlatformBase/PlatformBase.vcxproj
   sandbox/jng/clean_json/Common/PlatformBase/PlatformBase.vcxproj.filters
   sandbox/jng/clean_json/Common/PlatformBase/PlatformBaseBuild.cpp
   sandbox/jng/clean_json/Web/src/DotNetUnmanagedApi/PlatformBase/PlatformBaseApiGen.xml
   sandbox/jng/clean_json/Web/src/HttpHandler/HttpSelectFeatures.cpp
   sandbox/jng/clean_json/Web/src/HttpHandler/HttpSelectFeaturesSpatially.cpp
   sandbox/jng/clean_json/Web/src/HttpHandler/ReaderByteSourceImpl.cpp
   sandbox/jng/clean_json/Web/src/HttpHandler/ReaderByteSourceImpl.h
   sandbox/jng/clean_json/Web/src/MapGuideApi/MapGuideApiGen.xml
Log:
Add GeoJSON output support.

This is enabled when SELECTFEATURES is requested on the mapagent with CLEAN=1

The original (array-ified) JSON format is nigh on useless for consumption by client applications. Since CLEAN is global for all operations that can return JSON, it is more practical to return the results in the ubiquitous GeoJSON format when CLEAN=1

The GeoJSON writing functionality is also available in the PlatformBase component of the MapGuide API as the MgGeoJsonWriter class

Modified: sandbox/jng/clean_json/Common/PlatformBase/PlatformBase.h
===================================================================
--- sandbox/jng/clean_json/Common/PlatformBase/PlatformBase.h	2015-11-13 12:23:55 UTC (rev 8832)
+++ sandbox/jng/clean_json/Common/PlatformBase/PlatformBase.h	2015-11-18 14:34:10 UTC (rev 8833)
@@ -114,6 +114,7 @@
 #include "Services/FeatureServiceCommon.h"
 #include "Services/FeatureSet.h"
 #include "Services/FeatureSpatialOperations.h"
+#include "Services/GeoJsonWriter.h"
 #include "Services/GeometricPropertyDefinition.h"
 #include "Services/GeometryProperty.h"
 #include "Services/GeometryTypeInfo.h"

Modified: sandbox/jng/clean_json/Common/PlatformBase/PlatformBase.vcxproj
===================================================================
--- sandbox/jng/clean_json/Common/PlatformBase/PlatformBase.vcxproj	2015-11-13 12:23:55 UTC (rev 8832)
+++ sandbox/jng/clean_json/Common/PlatformBase/PlatformBase.vcxproj	2015-11-18 14:34:10 UTC (rev 8833)
@@ -556,6 +556,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="Services\GeoJsonWriter.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="Services\GeometricPropertyDefinition.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -915,6 +921,7 @@
     <ClInclude Include="Services\FeatureSourceParams.h" />
     <ClInclude Include="Services\FeatureSpatialOperations.h" />
     <ClInclude Include="Services\FileFeatureSourceParams.h" />
+    <ClInclude Include="Services\GeoJsonWriter.h" />
     <ClInclude Include="Services\GeometricPropertyDefinition.h" />
     <ClInclude Include="Services\GeometryProperty.h" />
     <ClInclude Include="Services\GeometryTypeInfo.h" />

Modified: sandbox/jng/clean_json/Common/PlatformBase/PlatformBase.vcxproj.filters
===================================================================
--- sandbox/jng/clean_json/Common/PlatformBase/PlatformBase.vcxproj.filters	2015-11-13 12:23:55 UTC (rev 8832)
+++ sandbox/jng/clean_json/Common/PlatformBase/PlatformBase.vcxproj.filters	2015-11-18 14:34:10 UTC (rev 8833)
@@ -349,6 +349,9 @@
       <Filter>MapLayer</Filter>
     </ClCompile>
     <ClCompile Include="PlatformBaseBuild.cpp" />
+    <ClCompile Include="Services\GeoJsonWriter.cpp">
+      <Filter>Services</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Data\BlobProperty.h">
@@ -730,6 +733,9 @@
       <Filter>MapLayer</Filter>
     </ClInclude>
     <ClInclude Include="PlatformBase.h" />
+    <ClInclude Include="Services\GeoJsonWriter.h">
+      <Filter>Services</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="PlatformBase.rc" />

Modified: sandbox/jng/clean_json/Common/PlatformBase/PlatformBaseBuild.cpp
===================================================================
--- sandbox/jng/clean_json/Common/PlatformBase/PlatformBaseBuild.cpp	2015-11-13 12:23:55 UTC (rev 8832)
+++ sandbox/jng/clean_json/Common/PlatformBase/PlatformBaseBuild.cpp	2015-11-18 14:34:10 UTC (rev 8833)
@@ -89,6 +89,7 @@
 #include "Services/FeatureSourceParams.cpp"
 #include "Services/FeatureSpatialOperations.cpp"
 #include "Services/FileFeatureSourceParams.cpp"
+#include "Services/GeoJsonWriter.cpp"
 #include "Services/GeometricPropertyDefinition.cpp"
 #include "Services/GeometryProperty.cpp"
 #include "Services/GeometryTypeInfo.cpp"

Added: sandbox/jng/clean_json/Common/PlatformBase/Services/GeoJsonWriter.cpp
===================================================================
--- sandbox/jng/clean_json/Common/PlatformBase/Services/GeoJsonWriter.cpp	                        (rev 0)
+++ sandbox/jng/clean_json/Common/PlatformBase/Services/GeoJsonWriter.cpp	2015-11-18 14:34:10 UTC (rev 8833)
@@ -0,0 +1,509 @@
+#include "PlatformBase.h"
+#include <algorithm>
+#include <iterator>
+#include <sstream>
+
+MgGeoJsonWriter::MgGeoJsonWriter()
+{
+    m_agfRw = new MgAgfReaderWriter();
+}
+
+STRING MgGeoJsonWriter::FeatureToGeoJson(MgFeatureReader* featureReader, MgTransform* transform)
+{
+    Ptr<MgClassDefinition> clsDef = featureReader->GetClassDefinition();
+    Ptr<MgPropertyDefinitionCollection> idProps = clsDef->GetIdentityProperties();
+    if (idProps->GetCount() == 1)
+    {
+        INT32 idx = 0;
+        Ptr<MgPropertyDefinition> idProp = idProps->GetItem(idx);
+        return FeatureToGeoJson(featureReader, transform, idProp->GetName(), clsDef->GetDefaultGeometryPropertyName());
+    }
+    else
+    {
+        return FeatureToGeoJson(featureReader, transform, L"", L"");
+    }
+}
+
+STRING MgGeoJsonWriter::FeatureToGeoJson(MgReader* reader, MgTransform* transform, CREFSTRING idPropertyName, CREFSTRING geomPropName)
+{
+    STRING ret;
+    INT32 idIndex = -1;
+    INT32 gIndex = -1;
+    STRING idVal;
+    STRING geomVal;
+
+    std::vector<STRING> propVals;
+
+    MG_TRY()
+
+        CHECKARGUMENTNULL(reader, L"MgGeoJsonWriter.FeatureToGeoJson");
+
+    if (!idPropertyName.empty())
+        idIndex = reader->GetPropertyIndex(idPropertyName);
+    if (!geomPropName.empty())
+    {
+        gIndex = reader->GetPropertyIndex(geomPropName);
+        if (gIndex >= 0)
+        {
+            //Must check out as a geometry property
+            INT32 propType = reader->GetPropertyType(gIndex);
+            if (propType != MgPropertyType::Geometry)
+                gIndex = -1;
+        }
+    }
+
+    //Pre-load id and geometry values first
+    if (idIndex >= 0 && !reader->IsNull(idIndex))
+    {
+        ValueToString(reader, idIndex, idVal);
+    }
+    if (gIndex >= 0 && !reader->IsNull(gIndex))
+    {
+        try
+        {
+            Ptr<MgByteReader> agf = reader->GetGeometry(gIndex);
+            Ptr<MgGeometry> geom;
+            if (NULL != transform)
+                geom = m_agfRw->Read(agf, transform);
+            else
+                geom = m_agfRw->Read(agf);
+            ToGeoJson(geom, geomVal);
+        }
+        catch (MgException* ex)
+        {
+            SAFE_RELEASE(ex);
+            geomVal = L"\"geometry\": null";
+        }
+    }
+
+    //Iterate the other properties, skipping over the geometry and id ones if they have been read
+    INT32 propCount = reader->GetPropertyCount();
+    for (INT32 i = 0; i < propCount; i++)
+    {
+        STRING name = reader->GetPropertyName(i);
+        INT32 propType = reader->GetPropertyType(i);
+        if (!reader->IsNull(i))
+        {
+            if (idIndex != i && gIndex != i) //Non id/Non geom property
+            {
+                //GeoJSON only allows one geometry
+                if (propType == MgPropertyType::Geometry && geomVal.empty())
+                {
+                    try
+                    {
+                        Ptr<MgByteReader> agf = reader->GetGeometry(i);
+                        Ptr<MgGeometry> geom;
+                        if (NULL != transform)
+                            geom = m_agfRw->Read(agf, transform);
+                        else
+                            geom = m_agfRw->Read(agf);
+                        ToGeoJson(geom, geomVal);
+                    }
+                    catch (MgException* ex)
+                    {
+                        SAFE_RELEASE(ex);
+                        geomVal = L"\"geometry\": null";
+                    }
+                }
+                else
+                {
+                    STRING propFragment = L"\"";
+                    propFragment += name;
+                    propFragment += L"\": ";
+
+                    STRING val;
+                    ValueToString(reader, i, val);
+                    propFragment += val;
+
+                    propVals.push_back(propFragment);
+                }
+            }
+        }
+        else //null property
+        {
+            STRING propFragment = L"\"";
+            propFragment += name;
+            propFragment += L"\": null";
+
+            propVals.push_back(propFragment);
+        }
+    }
+
+    ret = L"{ \"type\": \"Feature\", "; //START FEATURE
+    if (!idVal.empty())
+    {
+        ret += L"\"id\": ";
+        ret += idVal;
+        ret += L", ";
+    }
+    if (!geomVal.empty())
+    {
+        ret += geomVal;
+        ret += L", ";
+    }
+    ret += L"\"properties\": {"; //START PROPERTIES
+    switch (propVals.size())
+    {
+    case 0:
+        break;
+    case 1:
+        ret += propVals[0];
+        break;
+    default:
+        //Implode the vector to a comma-delimited string of "key": <value> pairs
+        std::wostringstream os;
+        std::ostream_iterator<STRING, wchar_t> outIt(os, L",");
+        std::copy(propVals.begin(), propVals.end() - 1, outIt);
+        os << *propVals.rbegin();
+        ret += os.str();
+        break;
+    }
+    ret += L"}"; //END PROPERTIES
+    ret += L"}"; //END FEATURE
+
+    MG_CATCH_AND_THROW(L"MgGeoJsonWriter.FeatureToGeoJson")
+
+    return ret;
+}
+
+void MgGeoJsonWriter::ValueToString(MgReader* reader, INT32 index, REFSTRING str)
+{
+    INT32 propType = reader->GetPropertyType(index);
+    switch (propType)
+    {
+    case MgPropertyType::Boolean:
+        {
+            str = reader->GetBoolean(index) ? L"true" : L"false";
+        }
+        break;
+    case MgPropertyType::Byte:
+        {
+            MgUtil::Int32ToString(reader->GetByte(index), str);
+        }
+        break;
+    case MgPropertyType::DateTime:
+        {
+            Ptr<MgDateTime> dt = reader->GetDateTime(index);
+            str = L"\"";
+            str += dt->ToString();
+            str += L"\"";
+        }
+        break;
+    case MgPropertyType::Decimal:
+    case MgPropertyType::Double:
+        {
+            double val = reader->GetDouble(index);
+            MgUtil::DoubleToString(val, str);
+        }
+        break;
+    case MgPropertyType::Int16:
+        {
+            INT16 val = reader->GetInt16(index);
+            MgUtil::Int32ToString(val, str);
+        }
+        break;
+    case MgPropertyType::Int32:
+        {
+            INT32 val = reader->GetInt32(index);
+            MgUtil::Int32ToString(val, str);
+        }
+        break;
+    case MgPropertyType::Int64:
+        {
+            INT64 val = reader->GetInt64(index);
+            MgUtil::Int64ToString(val, str);
+        }
+        break;
+    case MgPropertyType::Single:
+        {
+            float val = reader->GetSingle(index);
+            MgUtil::SingleToString(val, str);
+        }
+        break;
+    case MgPropertyType::String:
+        {
+            str = L"\"";
+            STRING strVal = EscapeJsonString(reader->GetString(index));
+            str += strVal;
+            str += L"\"";
+        }
+        break;
+    }
+}
+
+STRING MgGeoJsonWriter::EscapeJsonString(CREFSTRING input)
+{
+    std::wostringstream ss;
+    for (STRING::const_iterator iter = input.begin(); iter != input.end(); iter++)
+    {
+        switch (*iter)
+        {
+            case '\\': ss << L"\\\\"; break;
+            case '"': ss << L"\\\""; break;
+            case '/': ss << L"\\/"; break;
+            case '\b': ss << L"\\b"; break;
+            case '\f': ss << L"\\f"; break;
+            case '\n': ss << L"\\n"; break;
+            case '\r': ss << L"\\r"; break;
+            case '\t': ss << L"\\t"; break;
+            default: ss << *iter; break;
+        }
+    }
+    return ss.str();
+}
+
+void MgGeoJsonWriter::ToGeoJson(MgGeometry* geom, REFSTRING str, bool bIncludePrefix)
+{
+    STRING prefix;
+    if (bIncludePrefix)
+        prefix = L"\"geometry\": ";
+
+    INT32 geomType = geom->GetGeometryType();
+    switch (geomType)
+    {
+    case MgGeometryType::Point:
+        {
+            MgPoint* pt = (MgPoint*)geom;
+            Ptr<MgCoordinate> coord = pt->GetCoordinate();
+            str += prefix;
+            str += L"{ \"type\": \"Point\", \"coordinates\": ";
+            STRING strCoords;
+            CoordinateToGeoJson(coord, strCoords);
+            str += strCoords;
+            str += L"}";
+        }
+        break;
+    case MgGeometryType::LineString:
+        {
+            str += prefix;
+            str += L"{ \"type\": \"LineString\", \"coordinates\": ";
+            MgLineString* line = (MgLineString*)geom;
+            Ptr<MgCoordinateIterator> coords = line->GetCoordinates();
+            STRING strCoords;
+            CoordinatesToGeoJson(coords, strCoords);
+            str += strCoords;
+            str += L"}";
+        }
+        break;
+    case MgGeometryType::Polygon:
+        {
+            str += prefix;
+            str += L"{ \"type\": \"Polygon\", \"coordinates\": ";
+            MgPolygon* poly = (MgPolygon*)geom;
+            STRING strPoly;
+            PolygonToGeoJson(poly, strPoly);
+            str += strPoly;
+            str += L"}";
+        }
+        break;
+    case MgGeometryType::MultiPoint:
+        {
+            str += prefix;
+            str += L"{ \"type\": \"MultiPoint\", \"coordinates\": ";
+            MgMultiPoint* multi = (MgMultiPoint*)multi;
+            STRING strMulti;
+            MultiPointToGeoJson(multi, strMulti);
+            str += strMulti;
+            str += L"}";
+        }
+        break;
+    case MgGeometryType::MultiLineString:
+        {
+            str += prefix;
+            str += L"{ \"type\": \"MultiLineString\", \"coordinates\": ";
+            MgMultiLineString* multi = (MgMultiLineString*)geom;
+            STRING strMulti;
+            MultiLineStringToGeoJson(multi, strMulti);
+            str += strMulti;
+            str += L"}";
+        }
+        break;
+    case MgGeometryType::MultiPolygon:
+        {
+            str += prefix;
+            str += L"{ \"type\": \"MultiPolygon\", \"coordinates\": ";
+            MgMultiPolygon* multi = (MgMultiPolygon*)geom;
+            STRING strMulti;
+            MultiPolygonToGeoJson(multi, strMulti);
+            str += strMulti;
+            str += L"}";
+        }
+        break;
+    case MgGeometryType::MultiGeometry:
+        {
+            str += prefix;
+            str += L"{ \"type\": \"GeometryCollection\", \"geometries\": [";
+            MgMultiGeometry* multi = (MgMultiGeometry*)geom;
+            bool bFirst = true;
+            INT32 count = multi->GetCount();
+            for (INT32 i = 0; i < count; i++)
+            {
+                if (!bFirst)
+                    str += L",";
+
+                Ptr<MgGeometry> g = multi->GetGeometry(i);
+                STRING strGeom;
+                ToGeoJson(g, strGeom, false);
+
+                bFirst = false;
+            }
+            str += L"]";
+            str += L"}";
+        }
+        break;
+    default:
+        str = L"\"geometry\": null";
+        break;
+    }
+}
+
+void MgGeoJsonWriter::CoordinateToGeoJson(MgCoordinate* coord, REFSTRING str)
+{
+    str = L"[";
+    STRING sx;
+    MgUtil::DoubleToString(coord->GetX(), sx);
+    STRING sy;
+    MgUtil::DoubleToString(coord->GetY(), sy);
+    str += sx;
+    str += L", ";
+    str += sy;
+    str += L"]";
+}
+
+void MgGeoJsonWriter::CoordinatesToGeoJson(MgCoordinateIterator* coords, REFSTRING str)
+{
+    str = L"[";
+    bool bFirst = true;
+    while (coords->MoveNext())
+    {
+        if (!bFirst)
+            str += L",";
+
+        Ptr<MgCoordinate> coord = coords->GetCurrent();
+
+        str += L"[";
+        STRING sx;
+        MgUtil::DoubleToString(coord->GetX(), sx);
+        STRING sy;
+        MgUtil::DoubleToString(coord->GetY(), sy);
+        str += sx;
+        str += L", ";
+        str += sy;
+        str += L"]";
+
+        bFirst = false;
+    }
+    str += L"]";
+}
+
+void MgGeoJsonWriter::PolygonToGeoJson(MgPolygon* poly, REFSTRING str)
+{
+    str = L"[";
+
+    Ptr<MgRing> extRing = poly->GetExteriorRing();
+    if (NULL != extRing.p)
+    {
+        Ptr<MgCoordinateIterator> coords = extRing->GetCoordinates();
+        STRING strCoords;
+        CoordinatesToGeoJson(coords, strCoords);
+        str += strCoords;
+    }
+    INT32 irCount = poly->GetInteriorRingCount();
+    if (irCount > 0)
+    {
+        if (NULL != extRing.p)
+        {
+            str += L",";
+        }
+        for (INT32 i = 0; i < irCount; i++)
+        {
+            Ptr<MgRing> ir = poly->GetInteriorRing(i);
+            Ptr<MgCoordinateIterator> coords = ir->GetCoordinates();
+            STRING strCoords;
+            CoordinatesToGeoJson(coords, strCoords);
+            str += strCoords;
+            if (i < irCount - 1)
+            {
+                str += L",";
+            }
+        }
+    }
+    str += L"]";
+}
+
+void MgGeoJsonWriter::MultiPointToGeoJson(MgMultiPoint* multi, REFSTRING str)
+{
+    str = L"[";
+
+    bool bFirst = true;
+    INT32 count = multi->GetCount();
+    for (INT32 i = 0; i < count; i++)
+    {
+        if (!bFirst)
+            str += L",";
+
+        Ptr<MgPoint> point = multi->GetPoint(i);
+        Ptr<MgCoordinate> coord = point->GetCoordinate();
+        STRING coordStr;
+        CoordinateToGeoJson(coord, coordStr);
+
+        str += coordStr;
+
+        bFirst = false;
+    }
+
+    str += L"]";
+}
+
+void MgGeoJsonWriter::MultiLineStringToGeoJson(MgMultiLineString* multi, REFSTRING str)
+{
+    str = L"[";
+
+    bool bFirst = true;
+    INT32 count = multi->GetCount();
+    for (INT32 i = 0; i < count; i++)
+    {
+        if (!bFirst)
+            str += L",";
+
+        Ptr<MgLineString> line = multi->GetLineString(i);
+        Ptr<MgCoordinateIterator> coords = line->GetCoordinates();
+        STRING coordsStr;
+        CoordinatesToGeoJson(coords, coordsStr);
+
+        str += coordsStr;
+
+        bFirst = false;
+    }
+
+    str += L"]";
+}
+
+void MgGeoJsonWriter::MultiPolygonToGeoJson(MgMultiPolygon* multi, REFSTRING str)
+{
+    str = L"[";
+
+    bool bFirst = true;
+    INT32 count = multi->GetCount();
+    for (INT32 i = 0; i < count; i++)
+    {
+        if (!bFirst)
+            str += L",";
+
+        Ptr<MgPolygon> poly = multi->GetPolygon(i);
+        STRING strPoly;
+        
+        PolygonToGeoJson(poly, strPoly);
+
+        str += strPoly;
+
+        bFirst = false;
+    }
+
+    str += L"]";
+}
+
+void MgGeoJsonWriter::Dispose()
+{
+    delete this;
+}
\ No newline at end of file

Added: sandbox/jng/clean_json/Common/PlatformBase/Services/GeoJsonWriter.h
===================================================================
--- sandbox/jng/clean_json/Common/PlatformBase/Services/GeoJsonWriter.h	                        (rev 0)
+++ sandbox/jng/clean_json/Common/PlatformBase/Services/GeoJsonWriter.h	2015-11-18 14:34:10 UTC (rev 8833)
@@ -0,0 +1,47 @@
+//
+//  Copyright (C) 2004-2015 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef _MGGEOJSONWRITER_H
+#define _MGGEOJSONWRITER_H
+
+class MG_PLATFORMBASE_API MgGeoJsonWriter : public MgGuardDisposable
+{
+PUBLISHED_API:
+    MgGeoJsonWriter();
+
+    STRING FeatureToGeoJson(MgFeatureReader* featureReader, MgTransform* transform);
+
+    STRING FeatureToGeoJson(MgReader* reader, MgTransform* transform, CREFSTRING idPropertyName, CREFSTRING geomPropName);
+
+protected:
+    virtual void Dispose();
+
+private:
+    static STRING EscapeJsonString(CREFSTRING str);
+    void ValueToString(MgReader* reader, INT32 index, REFSTRING str);
+    void ToGeoJson(MgGeometry* geom, REFSTRING str, bool bIncludePrefix = true);
+    void CoordinateToGeoJson(MgCoordinate* coord, REFSTRING str);
+    void CoordinatesToGeoJson(MgCoordinateIterator* coords, REFSTRING str);
+    void PolygonToGeoJson(MgPolygon* poly, REFSTRING str);
+    void MultiPointToGeoJson(MgMultiPoint* multi, REFSTRING str);
+    void MultiLineStringToGeoJson(MgMultiLineString* multi, REFSTRING str);
+    void MultiPolygonToGeoJson(MgMultiPolygon* multi, REFSTRING str);
+
+    Ptr<MgAgfReaderWriter> m_agfRw;
+};
+
+#endif
\ No newline at end of file

Modified: sandbox/jng/clean_json/Web/src/DotNetUnmanagedApi/PlatformBase/PlatformBaseApiGen.xml
===================================================================
--- sandbox/jng/clean_json/Web/src/DotNetUnmanagedApi/PlatformBase/PlatformBaseApiGen.xml	2015-11-13 12:23:55 UTC (rev 8832)
+++ sandbox/jng/clean_json/Web/src/DotNetUnmanagedApi/PlatformBase/PlatformBaseApiGen.xml	2015-11-18 14:34:10 UTC (rev 8833)
@@ -146,6 +146,7 @@
     <Header path="../../../../Common/PlatformBase/Services/FeatureSchema.h" />
     <Header path="../../../../Common/PlatformBase/Services/FeatureSchemaCollection.h" />
     <Header path="../../../../Common/PlatformBase/Services/FeatureService.h" />
+    <Header path="../../../../Common/PlatformBase/Services/GeoJsonWriter.h" />
     <Header path="../../../../Common/PlatformBase/Services/GeometricPropertyDefinition.h" />
     <Header path="../../../../Common/PlatformBase/Services/GeometryProperty.h" />
     <Header path="../../../../Common/PlatformBase/Services/GeometryTypeInfo.h" />

Modified: sandbox/jng/clean_json/Web/src/HttpHandler/HttpSelectFeatures.cpp
===================================================================
--- sandbox/jng/clean_json/Web/src/HttpHandler/HttpSelectFeatures.cpp	2015-11-13 12:23:55 UTC (rev 8832)
+++ sandbox/jng/clean_json/Web/src/HttpHandler/HttpSelectFeatures.cpp	2015-11-18 14:34:10 UTC (rev 8833)
@@ -110,7 +110,7 @@
 
     Ptr<MgFeatureReader> featureReader = service->SelectFeatures(&resId, m_className, qryOptions);
     //MgByteSource owns this and will clean it up when done
-    ByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(featureReader, m_responseFormat);
+    ByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(featureReader, m_responseFormat, m_bCleanJson);
 
     Ptr<MgByteSource> byteSource = new MgByteSource(bsImpl);
     byteSource->SetMimeType(m_responseFormat);

Modified: sandbox/jng/clean_json/Web/src/HttpHandler/HttpSelectFeaturesSpatially.cpp
===================================================================
--- sandbox/jng/clean_json/Web/src/HttpHandler/HttpSelectFeaturesSpatially.cpp	2015-11-13 12:23:55 UTC (rev 8832)
+++ sandbox/jng/clean_json/Web/src/HttpHandler/HttpSelectFeaturesSpatially.cpp	2015-11-18 14:34:10 UTC (rev 8833)
@@ -120,7 +120,7 @@
 
     Ptr<MgDataReader> dataReader = service->SelectAggregate(&resId, m_className, qryOptions);
     //MgByteSource owns this and will clean it up when done
-    ByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(dataReader, m_responseFormat);
+    ByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(dataReader, m_responseFormat, m_bCleanJson);
 
     Ptr<MgByteSource> byteSource = new MgByteSource(bsImpl);
     byteSource->SetMimeType(m_responseFormat);

Modified: sandbox/jng/clean_json/Web/src/HttpHandler/ReaderByteSourceImpl.cpp
===================================================================
--- sandbox/jng/clean_json/Web/src/HttpHandler/ReaderByteSourceImpl.cpp	2015-11-13 12:23:55 UTC (rev 8832)
+++ sandbox/jng/clean_json/Web/src/HttpHandler/ReaderByteSourceImpl.cpp	2015-11-18 14:34:10 UTC (rev 8833)
@@ -17,7 +17,7 @@
 #include "ReaderByteSourceImpl.h"
 #include "PlatformBase.h"
 
-MgReaderByteSourceImpl::MgReaderByteSourceImpl(MgReader* reader, CREFSTRING format)
+MgReaderByteSourceImpl::MgReaderByteSourceImpl(MgReader* reader, CREFSTRING format, bool bCleanJson)
 {
     m_reader = SAFE_ADDREF(reader);
     m_format = format;
@@ -26,6 +26,7 @@
     m_bReadHeader = false;
     m_bInternalReaderHasMore = true;
     m_bFirstRecord = true;
+    m_bCleanJson = bCleanJson;
 }
 
 MgReaderByteSourceImpl::~MgReaderByteSourceImpl()
@@ -62,51 +63,67 @@
     {
         if (m_format == MgMimeType::Json)
         {
-            //How this looks:
-            //
-            // {                            //outer JSON start
-            //   "ResponseElementName":     //root element name
-            //     {                        //root JSON property start
-            //      <header JSON pair>,
-            //      "BodyElementName":[     //body JSON array start
-            //
-            jsonbuf = "{\"";
-            jsonbuf += m_reader->GetResponseElementName();
-            jsonbuf += "\":{";
-            m_reader->HeaderToStringUtf8(buf);
-            std::string jsonbuf2;
-            MgXmlJsonConvert convert;
-            convert.ToJson(buf, jsonbuf2);
-            //This will have redudant outer { }, so strip them
-            jsonbuf2.erase(0, 1);
-            jsonbuf2.erase(jsonbuf2.length() - 2, 1);
-            //HACK: To match the original output, we have to array-ify this object (crazy? yes!)
-            //
-            //We currently have something like this
-            //
-            // "HeaderElementName":{
-            //    <prop1>:<val1>,
-            //    <prop2>:<val2>
-            // }
-            //
-            //We have to change it to this
-            //
-            // "HeaderElementName":[{
-            //    <prop1>:<val1>,
-            //    <prop2>:<val2>
-            // }]
+            if (m_bCleanJson)
+            {
+                //How this looks:
+                //
+                // {
+                //   "type":"FeatureCollection",
+                //   "features": [
+                jsonbuf = "{";
+                jsonbuf += " \"type\": \"FeatureCollection\",";
+                jsonbuf += " \"features\": [";
 
-            //Find first instance of ": and insert [ after it. We use ": because a feature
-            //reader puts out xs:schema as the header element name
-            jsonbuf2.insert(jsonbuf2.find("\":") + 2, "[");
-            //Append ] to the end
-            jsonbuf2.append("]");
-            jsonbuf += jsonbuf2;
-            jsonbuf += ",\"";
-            jsonbuf += m_reader->GetBodyElementName();
-            jsonbuf += "\":[";
+                m_buf += jsonbuf;
+            }
+            else
+            {
+                //How this looks:
+                //
+                // {                            //outer JSON start
+                //   "ResponseElementName":     //root element name
+                //     {                        //root JSON property start
+                //      <header JSON pair>,
+                //      "BodyElementName":[     //body JSON array start
+                //
+                jsonbuf = "{\"";
+                jsonbuf += m_reader->GetResponseElementName();
+                jsonbuf += "\":{";
+                m_reader->HeaderToStringUtf8(buf);
+                std::string jsonbuf2;
+                MgXmlJsonConvert convert;
+                convert.ToJson(buf, jsonbuf2);
+                //This will have redudant outer { }, so strip them
+                jsonbuf2.erase(0, 1);
+                jsonbuf2.erase(jsonbuf2.length() - 2, 1);
+                //HACK: To match the original output, we have to array-ify this object (crazy? yes!)
+                //
+                //We currently have something like this
+                //
+                // "HeaderElementName":{
+                //    <prop1>:<val1>,
+                //    <prop2>:<val2>
+                // }
+                //
+                //We have to change it to this
+                //
+                // "HeaderElementName":[{
+                //    <prop1>:<val1>,
+                //    <prop2>:<val2>
+                // }]
 
-            m_buf += jsonbuf;
+                //Find first instance of ": and insert [ after it. We use ": because a feature
+                //reader puts out xs:schema as the header element name
+                jsonbuf2.insert(jsonbuf2.find("\":") + 2, "[");
+                //Append ] to the end
+                jsonbuf2.append("]");
+                jsonbuf += jsonbuf2;
+                jsonbuf += ",\"";
+                jsonbuf += m_reader->GetBodyElementName();
+                jsonbuf += "\":[";
+
+                m_buf += jsonbuf;
+            }
             m_bReadHeader = true;
         }
         else if (m_format == MgMimeType::Xml)
@@ -147,35 +164,62 @@
         {
             if (m_format == MgMimeType::Json)
             {
-                m_reader->CurrentToStringUtf8(buf);
-                //The body is a valid full XML element, so no need for gymnastics like its
-                //surrounding elements
-                MgXmlJsonConvert convert;
-                convert.ToJson(buf, jsonbuf);
+                if (m_bCleanJson)
+                {
+                    MgGeoJsonWriter geoJsonWriter;
+                    STRING sGeoJson;
+                    if (m_reader->GetReaderType() == MgReaderType::FeatureReader)
+                    {
+                        MgFeatureReader* fr = static_cast<MgFeatureReader*>(m_reader.p);
+                        sGeoJson = geoJsonWriter.FeatureToGeoJson(fr, NULL);
+                    }
+                    else 
+                    {
+                        sGeoJson = geoJsonWriter.FeatureToGeoJson(m_reader, NULL, L"", L"");
+                    }
 
-                //Strip outer { }
-                jsonbuf.erase(0, 1);
-                jsonbuf.erase(jsonbuf.length() - 2, 1);
-                //HACK: Same as the header, this needs to be array-ified to match the old output
-                //
-                //Find first instance of ": and insert [ after it.
-                jsonbuf.insert(jsonbuf.find("\":") + 2, "[");
-                //Append ] to the end
-                jsonbuf.append("]");
-                //Put back in outer { }
-                jsonbuf = "{" + jsonbuf;
-                jsonbuf += "}";
-
-                if (!m_bFirstRecord)
-                {
-                    m_buf += ",";
+                    if (!m_bFirstRecord)
+                    {
+                        m_buf += ",";
+                    }
+                    else
+                    {
+                        m_bFirstRecord = false;
+                    }
+                    m_buf += MgUtil::WideCharToMultiByte(sGeoJson);
                 }
                 else
                 {
-                    m_bFirstRecord = false;
+                    m_reader->CurrentToStringUtf8(buf);
+                    //The body is a valid full XML element, so no need for gymnastics like its
+                    //surrounding elements
+                    MgXmlJsonConvert convert;
+                    convert.ToJson(buf, jsonbuf);
+
+                    //Strip outer { }
+                    jsonbuf.erase(0, 1);
+                    jsonbuf.erase(jsonbuf.length() - 2, 1);
+                    //HACK: Same as the header, this needs to be array-ified to match the old output
+                    //
+                    //Find first instance of ": and insert [ after it.
+                    jsonbuf.insert(jsonbuf.find("\":") + 2, "[");
+                    //Append ] to the end
+                    jsonbuf.append("]");
+                    //Put back in outer { }
+                    jsonbuf = "{" + jsonbuf;
+                    jsonbuf += "}";
+
+                    if (!m_bFirstRecord)
+                    {
+                        m_buf += ",";
+                    }
+                    else
+                    {
+                        m_bFirstRecord = false;
+                    }
+
+                    m_buf += jsonbuf;
                 }
-
-                m_buf += jsonbuf;
             }
             else if (m_format == MgMimeType::Xml)
             {
@@ -192,11 +236,21 @@
         {
             if (m_format == MgMimeType::Json)
             {
-                // How this looks:
-                //      ]   //End of body JSON array
-                //    }     //End of root JSON property
-                // }        //End of outer JSON
-                m_buf += "]}}";
+                if (m_bCleanJson)
+                {
+                    // How this looks:
+                    //   ]  //End of root FeatureCollection
+                    // } //End of GeoJSON
+                    m_buf += "]}";
+                }
+                else
+                {
+                    // How this looks:
+                    //      ]   //End of body JSON array
+                    //    }     //End of root JSON property
+                    // }        //End of outer JSON
+                    m_buf += "]}}";
+                }
             }
             else if (m_format == MgMimeType::Xml)
             {

Modified: sandbox/jng/clean_json/Web/src/HttpHandler/ReaderByteSourceImpl.h
===================================================================
--- sandbox/jng/clean_json/Web/src/HttpHandler/ReaderByteSourceImpl.h	2015-11-13 12:23:55 UTC (rev 8832)
+++ sandbox/jng/clean_json/Web/src/HttpHandler/ReaderByteSourceImpl.h	2015-11-18 14:34:10 UTC (rev 8833)
@@ -29,7 +29,7 @@
     DECLARE_CLASSNAME(MgReaderByteSourceImpl)
 
 public:
-    MgReaderByteSourceImpl(MgReader* reader, CREFSTRING format);
+    MgReaderByteSourceImpl(MgReader* reader, CREFSTRING format, bool bCleanJson);
     virtual ~MgReaderByteSourceImpl();
 
     ///////////////////////////////////////////////////////////////////////////
@@ -85,6 +85,7 @@
 
     Ptr<MgReader> m_reader;
     STRING m_format;
+    bool m_bCleanJson;
     bool m_bReadHeader;
     bool m_bInternalReaderHasMore;
     bool m_bFirstRecord;

Modified: sandbox/jng/clean_json/Web/src/MapGuideApi/MapGuideApiGen.xml
===================================================================
--- sandbox/jng/clean_json/Web/src/MapGuideApi/MapGuideApiGen.xml	2015-11-13 12:23:55 UTC (rev 8832)
+++ sandbox/jng/clean_json/Web/src/MapGuideApi/MapGuideApiGen.xml	2015-11-18 14:34:10 UTC (rev 8833)
@@ -323,6 +323,7 @@
     <Header path="../../../Common/PlatformBase/Services/FeatureSchema.h" />
     <Header path="../../../Common/PlatformBase/Services/FeatureSchemaCollection.h" />
     <Header path="../../../Common/PlatformBase/Services/FeatureService.h" />
+    <Header path="../../../Common/PlatformBase/Services/GeoJsonWriter.h" />
     <Header path="../../../Common/PlatformBase/Services/GeometricPropertyDefinition.h" />
     <Header path="../../../Common/PlatformBase/Services/GeometryProperty.h" />
     <Header path="../../../Common/PlatformBase/Services/GeometryTypeInfo.h" />



More information about the mapguide-commits mailing list