44

I'm creating a web map using Leaflet, and I want to be able to grab feature layers from our ArcServer. I have successfully been able to retrieve a feature class as JSON, but Esri's JSON objects don't follow the GeoJSON standards so they cannot be displayed.

Does anyone know of a conversion script or tool that handles this?

If not, I plan on creating a script to convert ArcServer JSON objects to GeoJSON.

  • I was having trouble getting ogr2ogr to eat ESRI json coming from a MapServer feature query. (@SasaIvetic's example uses a FeatureServer request, and the MapServer result I need to consume must not have been interchangeable.) Anyway, this site totally did the trick: http://ogre.adc4gis.com/ – elrobis Oct 12 '15 at 16:08

13 Answers 13

40

OGR:

ogr2ogr -f GeoJSON test.json "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Hydrography/Watershed173811/FeatureServer/0/query?where=objectid+%3D+objectid&outfields=*&f=json" OGRGeoJSON

That command will read the query result directly from the URL. You can also supply it with a text file containing your JSON or you can directly supply encoded JSON on the command line. You can of course use ORG Python bindings to automate it within a script if necessary, or the library to do it in code.

For those that like web services, see Ogre an ogr2ogr web client which can convert json to geojson to and back, as well as geojson to shapefile.

Reference: http://www.gdal.org/drv_geojson.html

  • I downloaded FWTools. When I run that command, I get the error 'Unable to open datasource 'My URL here' with the following drivers. -> ESRI Shapefile -> MapInfo File -> UK .NTF -> SDTS -> TIGER -> S57 -> DGN -> VRT -> REC -> Memory -> BNA -> CSV -> NAS -> GML -> GPX -> KML -> GeoJSON -> Interlis 1 -> Interlis 2 -> GMT -> SQLite -> ODBC -> PGeo -> OGDI -> PostgreSQL -> MySQL -> XPlane -> AVCBin -> AVCE00 -> DXF -> Geoconcept -> GeoRSS -> GPSTrackMaker -> VFK I don't see something like 'ESRI JSON' in the list of drivers. – Tanner Aug 3 '11 at 20:15
  • 1
    @Tanner: FWTools comes with OGR v1.7 where GeoJSON support was added with v1.8.0. I'm running GDAL/OGR 1.9dev here, though not through FWTools. I think I got them from gisinternals.com/sdk – Sasa Ivetic Aug 3 '11 at 20:33
  • Thanks. I got this to work on the command line. I'm still working on getting it to work in my Javascript - any tips would be appreciated. – Tanner Aug 4 '11 at 18:03
  • @Tanner how did you get past that error? It's not a version issue for me but I'm getting the same error on my windows machine – kflaw Jun 22 '16 at 19:45
  • @kflaw Sorry, but I don't recall exactly. I think I just used ogr2ogr on the command line, and didn't need or use FWTools. – Tanner Jun 23 '16 at 17:19
7

You can also see Esri's geojson-utils on Github that "contains [javascript] utilities for converting GeoJSON to other geographic json formats and vice versa. Currently only GeoJSON to Esri JSON has been developed. Also, note that only geometries in the WGS84 coordinate system are supported."

5

ESRI JSON to GeoJSON (for OpenLayers) *Likely to be modified for Leaflet javascript

        //create esri JSON object
    var myReturn = "esriObj = "+xmlHttpGet(restCall, false);
    eval(myReturn);

I can now work with esriObj as a JSON object i.e. esriObj.geometryType. What happens in the xmlHttpGet method? Basically I create a XMLHttpRequest and pass in my REST URL – your can see this code here

3. OK i have my ‘ESRI query’ JSON object now I need to parse the features in this object and essentially create GeoJSON strings which the OpenLayers sample will be happy with – cue the code butchery…


function esriDeserialize(geojson)
{

    var element = document.getElementById('text');
    var type = document.getElementById("formatType").value;
    var features = formats['in'][type].read(geojson);
    var bounds;
    if(features)
    {
        if(features.constructor != Array) {
            features = [features];
        }
        for(var i=0; i<features.length;>
            if (!bounds) {
                bounds = features[i].geometry.getBounds();
            } else {
                bounds.extend(features[i].geometry.getBounds());
            }

        }
        vectors.addFeatures(features);
        //map.zoomToExtent(bounds);
        var plural = (features.length &gt; 1) ? 's' : '';
        //element.value = features.length + ' feature' + plural + ' added'
    } else {
        element.value = 'Bad input ' + type;
    }
}

function getEsriGeom(restCall){

    //call ESRI Rest API
    //"http://pc302926/ArcGIS/rest/services/worldadmin/MapServer/0/query?text=&amp;geometry=&amp;geometryType=esriGeometryEnvelope&amp;inSR=&amp;spatialRel=esriSpatialRelIntersects&amp;where=%22FIPS_CNTRY%22+%3D+%27AS%27&amp;returnGeometry=true&amp;outSR=4326&amp;outFields=&amp;f=json"
    var element = document.getElementById('text');  

    //create esri JSON object
    var myReturn = "esriObj = "+xmlHttpGet(restCall, false);
    eval(myReturn);

    element.value = "";
    var coordPairsPerFeature = 0;

    //for each feature
    for (var i=0; i &lt; esriObj.features.length; i++)
    {
        //get the geometry
        var o = esriObj.features[i].geometry;
        element.value = element.value + esriObj.features[i].attributes.ADMIN_NAME;

        //loop through all the rings
        for (var s=0; s &lt; o.rings.length; s++)
        {
            //create geojson start &amp; end - i know i'm getting polygons
            var geojsonstart = '{"type":"Feature", "id":"OpenLayers.Feature.Vector_124", "properties":{}, "geometry":{"type":"Polygon", "coordinates":[['
            var geojsonend = ']]}, "crs":{"type":"OGC", "properties":{"urn":"urn:ogc:def:crs:OGC:1.3:CRS84"}}}';

            //the coordinates for this ring
            var coords = o.rings[s];

            //loop through each coordinate
            var coordPair="";
            for (var g=0; g &lt; coords.length; g++)
            {
                coordPairsPerFeature = coordPairsPerFeature+1;

                //alert(coords[g]);
                if(g==coords.length-1){
                    coordPair = coordPair+"["+coords[g]+"]";
                }else{
                    coordPair=coordPair+"["+coords[g]+"],";
                }
            }

            //combine to create geojson string
            esriDeserialize(geojsonstart+coordPair+geojsonend);
        }

        element.value = element.value + "," + coordPairsPerFeature +"n";
    }

}
</features.length;>

source: http://mapbutcher.com/blog/?p=62

5

ArcGIS now supports GeoJSON

Now ArcGIS Online has GeoJSON through ArcGIS Rest API URL. All you need to do is set f=geojson in the URL and configure the service. Be aware, by default, ArcGIS online will not allow GeoJSON export until you explicit permit other output formats.

Here is how to enable the export:

  1. Log into arcgis online
  2. click the feature layers,
  3. click the setting tab
  4. check this box that says

    Export Data

    Allow others to export to different formats.

  5. Save and wait a few minutes.

In the query page, you should see the output format dropdown list with the GeoJSON option. The old was called json.

  • Is a agol rest service different from an ArcGIS server rest service? Can only agol provide geoJSON as a rest service and not server? – jotamon Mar 29 '18 at 23:57
4

Leaflet and ArGIS vector layer.

https://github.com/JasonSanford/leaflet-vector-layers

Working demo. http://geojason.info/leaflet-vector-layers/demos/arcgis-server/

More on Leaflet and ArcGIS.

  • Leaflet and ArcGIS Server layers i.e. AgsDynamicLayer and AgsFeatureLayer.

You can get this fork which has support for ArcGIS server.

https://github.com/dtsagile/Leaflet/

 var sitesLayer = new L.AgsDynamicLayer(
    'http://ags2.dtsagile.com/ArcGIS/rest/services/LiveFeeds/WxMappr/MapServer',
    { maxZoom: 19,
        attribution: "NOAA",
        opacity: 1,
        layers: 'show:2' });
_map.addLayer(sitesLayer);

http://blog.davebouwman.com/2011/08/04/leaflet-lean-mean-javascript-maps/

ArcGIS Image Services and Leaflet http://blog.geomusings.com/2012/04/17/arcgis-image-services-and-leaflet/

3

I've built a server object extension to generate GeoJSON from ArcGIS Server map services. It's been tested with 10.1 and 10.2 but not earlier. https://github.com/geobabbler/AGSOpenFormats

3

For a one-time conversion I would have used the accepted answer from @Sasa Ivetic but needed something real-time, and Terraformer worked decently for that. Unfortunately it's only for single features by default, so for multiple features you need to loop through the array and add an ID to each feature:

var FeatureCollection = {
  type: "FeatureCollection",
  features: []
}

for (var i = 0; i < arcgis.features.length; i++) {
  var feature = Terraformer.ArcGIS.parse(arcgis.features[i]);
  feature.id = i;
  FeatureCollection.features.push(feature)
};

This worked fine for me except on multi-part polygons (i.e. Alaska and its islands), but I'm new to this so it's possible I coded something incorrectly!

2

Its usually* pretty easy converting.

I made a script https://github.com/calvinmetcalf/esri2geo and there are others that work well too.

*The exception is multi-part polygons with holes which don't convert 1-to-1 without some geoprocessing.

2

Converting ArcGIS JSON to GeoJSONThere in pure Browser

there are 2 ways you can do

1) TERRAFORMER

Note: use in node.js and use in browser are different, details see link

2) Esri/arcgis-to-geojson-utils

use in browser, ArcgisToGeojsonUtils is global var reference the entry point of this module

<script src="https://unpkg.com/@esri/arcgis-to-geojson-utils@1.2.0/dist/arcgis-to-geojson.js"></script>

// parse ArcGIS JSON, convert it to GeoJSON
const geojson = ArcgisToGeojsonUtils.arcgisToGeoJSON({
"x":-122.6764,
"y":45.5165,
"spatialReference": {
  "wkid": 4326
}

});

However, if you want to bundle by yourself, just for learning, follow steps

a) You need to compile all the module source file into a single bundle.js

rollup.js install by

npm install --global rollup

then go to your js lib root folder, find the entry point js file, in this case it is index.js

$ rollup index.js --format umd --name "esri_arcgis_to_geojson" --file bundle.js

You should find a new file bundle.js in your root directory.

Now in your browser html file, include this bundle.js file

<script src='.../.../.../bundle.js'>

You can use it now by

  // parse ArcGIS JSON, convert it to GeoJSON
  var geojson = esri_arcgis_to_geojson.arcgisToGeoJSON({
                            "x":-122.6764,
                            "y":45.5165,
                            "spatialReference": {
                              "wkid": 4326
                            }
                            });

 // take GeoJSON and convert it to ArcGIS JSON
  var arcgis = esri_arcgis_to_geojson.geojsonToArcGIS({
                            "type": "Point",
                              "coordinates": [45.5165, -122.6764]
                            });enter code here

Remember esri_arcgis_to_geojson is the name you named the lib

This becomes the global variable name, available in browser.

The trick is, bundle process add instant implement function like (function xx {}) here is the top part from bundle.js

  (function (global, factory) {
     typeof exports === 'object' && typeof module !== 'undefined' ? 
        factory(exports) :
      typeof define === 'function' && define.amd ? define(['exports'], 
         factory) :
      (factory((global.arcgis_to_geojson = {})));
      }(this, (function (exports) { 'use strict';

         ***ORIGINAL SOURCE CODE OF JS MODULE***

     })));

arcgis-to-geojson-utils

1

If its a one time query and you don't have more than 1000 features try pasting this into qgis by using the add vector layer - choose protocol and replace this arcgis rest URL with yours: http://geodata.epa.gov/arcgis/rest/services/OAR/USEPA_NEI_2005/MapServer/1/query?where=objectid+%3D+objectid&outfields=*&f=json ... This assumes you have gdal 1.10 installed

1

Perhaps even easier you can use the Esri-leaflet library to add it natively as a layer in Leaflet.

We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is right, ideally with citations. Answers that don't include explanations may be removed.

  • 2
    Could you incorporate an example in your post outlining how this answer's the OP's question? – Paul Sep 26 '13 at 18:00
0

If all you need is to return the ArcServer Service as a GeoJSON to use in whichever mapping tech you want, I highly recommend you look at this GitHub issue dialogue.

I am not going to replicate the dialogue here because that would waste time. Your options are clearly laid out there directly from Esri.

-1

arcgis server rest api, feature service,

if you query the layer, with URL like this, .../FeatureServer/query?layerDefs=...

http://services3.arcgis.com/your_token/arcgis/rest/services/Parcels/FeatureServer/query?layerDefs={"0":""}&returnGeometry=true&f=pgeojson&geometryType=esriGeometryEnvelope&geometry={"xmin" : -117.923158, "ymin" : 33.644081, "xmax" : -117.921436, "ymax" : 33.645157,"spatialReference" : {"wkid" : 4326}}

You can not set geojson format, f=pgeojson will be bad request, f=json, because the return stuff is not feature, the layers json was return.

Try this html query page, you can see, no geojson option,

 http://services3.arcgis.com/you_token/arcgis/rest/services/Parcels/FeatureServer/query

If you want to return geojson (feature), you must use this URL .../FeatureServer/0/query...

/0/ means layerID, if on has only 1 layer, then layerID = 0.....

Try this html query page, you can see, geojson is option, because you are query specific layer with layerID = 0

http://services3.arcgis.com/your_token/arcgis/rest/services/Parcels/FeatureServer/0/query

Note: remember to set those 2 parameters: outSR=4326&f=geojson in the URL spatial reference ID, srid = 4326, because web map all use this, f means format, both f=pgeojson and f=geojson works. If you don't set outSR=4326, arcgis server rest api by default will NOT use 4326, instead use something else, only 4326 has unit degree, which is used in most web map. Other format would not work with web maps.

By the way, for those want to use arcgis server rest api with tile service,

tilestream and others

/zoom(z)/x/y.png

http://localhost/v2/city_parcels/12/706/1641.png

arcgis server tile service: no png, x and y in different order

     /zoom(z)/y/x

http://services3.arcgis.com/your_token/ArcGIS/rest/services/Parcels/MapServer/tile/12/1641/706

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.