1

I have a script that obtains feature data from a JSON output of an ArcGIS REST MapServer. At present my script treats the JSON data as a "LineString" Geometry type, but, the JSON data is in fact a "MultiLineString" Geometry type. How do I force my script to treat the data as "MultiLineString"? My current script is:

import ogr

url = 'http://maps.six.nsw.gov.au/arcgis/rest/services/sixmaps/LPIMap/MapServer/16/query?geometry=16501408.594,-4372525.989,16523000,-4320000&geometryType=esriGeometryEnvelope&f=pjson&outFields=functionhierarchy,OBJECTID,shape,roadontype,roadnamestring,shape_Length'

ds = ogr.Open(url)
lyr = ds.GetLayer()

if (lyr.GetGeomType() == ogr.wkbLineString):
    print ('line')
elif (lyr.GetGeomType() == ogr.wkbMultiLineString):
    print ('multiline')
else:
    print ('neithor line nor multiline')

del ds, lyr   

The JSON data is a MultiLineString type as it consists of seperate lists of many cordinates within a large single list. For example, the JSON output below shows the end of one list of coordinates and the beginning of a subsequent list of coordinates and is a component of the first feature reported in the URL in the script above.

 [
   16504625.024250001,
   -4372770.7781249993
  ],
  [
   16504645.846749999,
   -4372777.386500001
  ],
  [
   16504664.026874997,
   -4372785.385625001
  ]
 ],
 [
  [
   16504684.332374997,
   -4372794.3222500011
  ],
  [
   16504706.535875,
   -4372804.0945000015
  ],
  [
   16504730.744125001,
   -4372813.5017499998
  ],

Because the script treats the data as a "LineString" different sections of the the same paths are connected by relatively long straight lines. An example of the these erroneous relatively long straight lines are shown in the picture below which is a plot of the features in the layer as interpreted by the script. enter image description here

  • Data from that URL comes from ESRI REST service, not from the open source MapServer server, if your tag refers to that. By looking at the returned data all 371 features are linestrings. What makes you think that they are multilinestrings? – user30184 Jul 22 '16 at 21:09
  • I believe that they are MultiLineStrings as the data for discrete features consists of lists of many coordinates within a larger list for the feature. This structure is evident by opening the URL in a browser and scrolling down. Furthermore, if you plot the layer obtained by the script with QGIS or ArcGIS you will observe lines that connect non-neighboring sections of the features. In this case the features are roads. – Philip Whitten Jul 23 '16 at 3:19
  • I have changed one of the tags and the question to distinguish the ESRI REST MapServer from the better known open source MapServer. – Philip Whitten Jul 23 '16 at 3:20
  • Thanks for showing that the json data has line parts separated with ] ], [ [. Looks like a bug in GDAL. – user30184 Jul 23 '16 at 7:40
1

The following code will parse an ArcGIS (ESRI) REST MapServer MultiLineString JSON url so that it can be read by the GDAL GeoJSON driver. The code achieves this by constructing a new JSON object and copying the relevant data from the ArcGIS REST MapServer JSON url. This could be easily turned into a function.

import ogr
import urllib, json

url = 'http://maps.six.nsw.gov.au/arcgis/rest/services/sixmaps/LPIMap/MapServer/16/query?geometry=16501408.594,-4372525.989,16523000,-4320000&geometryType=esriGeometryEnvelope&f=pjson&outFields=functionhierarchy,OBJECTID,shape,roadontype,roadnamestring,shape_Length'

response = urllib.urlopen(url)
data = json.loads(response.read())
data1 = {}
data1['type'] = 'FeatureCollection'
#set coordinate reference system
if data[u'spatialReference'][u'wkid'] == 102100:
    data1['crs'] = {}
    data1['crs']['type']='EPSG'
    data1['crs']['properties']={'code': 7483}
else:
    data1['crs'] = data[u'spatialReference']

data1['features'] = []          
for i in range(feat_no):
    data1['features'].insert(i, {})
    data1['features'][i]['type']='Feature'
    data1['features'][i]['geometry']={}
    data1['features'][i]['geometry']['type']='MultiLineString'
    data1['features'][i]['geometry']['coordinates'] = data[u'features'][i][u'geometry'][u'paths']
    data1['features'][i]['properties']={}
    # I don't know how to set attribute data types or lengths
    for item in data[u'features'][i][u'attributes']:
        data1['features'][i]['properties'][item]=data[u'features'][i][u'attributes'][item]

data1 = json.dumps(data1)
ds = ogr.Open(data1)
lyr = ds.GetLayer()

del ds, lyr  
1

There was indeed a bug in reading ESRI JSON MultiLinestrings with GDAL. It has now corrected in GDAL trunk (version 2.2-dev) with changeset https://trac.osgeo.org/gdal/changeset/34773. No backports have been done to 1.11, 2.0, or 2.1 series.

Despite the problem with multilinestrings GDAL seems to read ESRI JSON quite well. Test with the following JSON

{
 "displayFieldName": "roadnamestring",
 "fieldAliases": {
  "functionhierarchy": "FunctionHierarchy",
  "OBJECTID": "OBJECTID",
  "roadontype": "RoadOnType",
  "roadnamestring": "roadnamestring",
  "shape_Length": "shape_Length"
 },
 "geometryType": "esriGeometryPolyline",
 "spatialReference": {
  "wkid": 3857,
  "latestWkid": 3857
 },
 "fields": [
  {
   "name": "functionhierarchy",
   "type": "esriFieldTypeSmallInteger",
   "alias": "FunctionHierarchy"
  },
  {
   "name": "OBJECTID",
   "type": "esriFieldTypeOID",
   "alias": "OBJECTID"
  },
  {
   "name": "roadontype",
   "type": "esriFieldTypeSmallInteger",
   "alias": "RoadOnType"
  },
  {
   "name": "roadnamestring",
   "type": "esriFieldTypeString",
   "alias": "roadnamestring",
   "length": 80
  },
  {
   "name": "shape_Length",
   "type": "esriFieldTypeDouble",
   "alias": "shape_Length"
  }
 ],
 "features": [
  {
   "attributes": {
    "functionhierarchy": 4,
    "OBJECTID": 2857,
    "roadontype": 1,
    "roadnamestring": "ALPINE WAY",
    "shape_Length": 121053.94010502081
   },
   "geometry": {
    "paths": [
     [
      [
       16490352.71125,
       -4374934.9532499984
      ],
      [
       16490354.657125004,
       -4374949.0618750006
      ],
      [
       16490364.728625,
       -4374975.3704999983
      ],
      [
       16490377.779749997,
       -4374991.6128749996
      ],
      [
       16490395.435874999,
       -4375003.0787499994
      ],
      [
       16490411.941624999,
       -4375010.7230000012
      ]
           ]
          ]
         }
        }
       ]
}

Ogrinfo finds the SRS and attributes:

ogrinfo esritest.json -al -so
INFO: Open of `esritest.json'
      using driver `GeoJSON' successful.

Layer name: OGRGeoJSON
Geometry: Line String
Feature Count: 1
Extent: (16490352.711250, -4375010.723000) - (16490411.941625, -4374934.953250)
Layer SRS WKT:
PROJCS["WGS 84 / Pseudo-Mercator",
    GEOGCS["WGS 84",
        DATUM["WGS_1984",
            SPHEROID["WGS 84",6378137,298.257223563,
                AUTHORITY["EPSG","7030"]],
            AUTHORITY["EPSG","6326"]],
        PRIMEM["Greenwich",0,
            AUTHORITY["EPSG","8901"]],
        UNIT["degree",0.0174532925199433,
            AUTHORITY["EPSG","9122"]],
        AUTHORITY["EPSG","4326"]],
    PROJECTION["Mercator_1SP"],
    PARAMETER["central_meridian",0],
    PARAMETER["scale_factor",1],
    PARAMETER["false_easting",0],
    PARAMETER["false_northing",0],
    UNIT["metre",1,
        AUTHORITY["EPSG","9001"]],
    AXIS["X",EAST],
    AXIS["Y",NORTH],
    EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +
x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],
    AUTHORITY["EPSG","3857"]]
FID Column = OBJECTID
functionhierarchy: Integer (0.0)
OBJECTID: Integer (0.0)
roadontype: Integer (0.0)
roadnamestring: String (80.0)
shape_Length: Real (0.0)
  • That is good news and a quick response. I am now aware that ESRI's JSON template is rather different to the open source GeoJSON template. Is there any possibility or motivation for the GDAL drivers to read other details like the spatial reference or field data types from ESRI JSON type url's? – Philip Whitten Jul 26 '16 at 3:56
  • I don't know anything about ESRI JSON really. By a quick test with your data GDAL seems to do good work, see the edited answer. – user30184 Jul 26 '16 at 4:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.