Sean Gillies (Posts about http)https://sgillies.net/tags/http.atom2023-12-31T01:26:21ZSean GilliesNikolaThe GeoJSON media typehttps://sgillies.net/2014/05/22/the-geojson-media-type.html2014-05-22T00:00:00-06:002014-05-22T00:00:00-06:00Sean Gillies<p>It's official: <a class="reference external" href="http://www.iana.org/assignments/media-types/application/vnd.geo+json">application/vnd.geo+json</a> is
the media type for GeoJSON registered with the IANA. I had been holding out for
a <a class="reference external" href="https://www.mnot.net/blog/2012/04/17/profiles">profile</a> of
application/json, but it seems that the internet has resigned itself to
a Cambrian explosion of JSON media types.</p>
<p>Start serving your GeoJSON up with the new content type</p>
<pre class="literal-block">HTTP/1.1 200 OK
Content-Type: application/vnd.geo+json</pre>
<p>and start asking for it by name.</p>
<pre class="literal-block">Accept: application/vnd.geo+json; q=1.0, application/json; q=0.5</pre>
<p><strong>Update</strong> (2019-11-13): Since the publication of <a class="reference external" href="https://tools.ietf.org/html/rfc7946">RFC 7946</a> GeoJSON has a new official media type,
application/geo+json.</p>Some consequences of GeoJSON features as arrayshttps://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html2013-12-06T00:00:00-07:002013-12-06T00:00:00-07:00Sean Gillies<p>Don't mind me, I'm just thinking out loud about the GeoJSON format.</p>
<p>A GeoJSON Feature Collection is an object with a "features" key and the value
for the key is specified to be an array of Feature objects. Is the order of
Features significant? In the context of my <a class="reference external" href="http://sgillies.net/blog/2013/12/04/json-diff-and-patch-for-geojson.html">previous post</a>,
should a zero or empty RFC 6902 diff between this</p>
<div class="code"><pre class="code javascript"><a id="rest_code_23f90d7361a5468995d9a90765d69528-1" name="rest_code_23f90d7361a5468995d9a90765d69528-1" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_23f90d7361a5468995d9a90765d69528-1"></a><span class="p">{</span><span class="w"> </span><span class="s2">"type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"FeatureCollection"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_23f90d7361a5468995d9a90765d69528-2" name="rest_code_23f90d7361a5468995d9a90765d69528-2" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_23f90d7361a5468995d9a90765d69528-2"></a><span class="w"> </span><span class="s2">"features"</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="w"></span>
<a id="rest_code_23f90d7361a5468995d9a90765d69528-3" name="rest_code_23f90d7361a5468995d9a90765d69528-3" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_23f90d7361a5468995d9a90765d69528-3"></a><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Feature"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_23f90d7361a5468995d9a90765d69528-4" name="rest_code_23f90d7361a5468995d9a90765d69528-4" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_23f90d7361a5468995d9a90765d69528-4"></a><span class="w"> </span><span class="s2">"id"</span><span class="o">:</span><span class="w"> </span><span class="s2">"foo"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_23f90d7361a5468995d9a90765d69528-5" name="rest_code_23f90d7361a5468995d9a90765d69528-5" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_23f90d7361a5468995d9a90765d69528-5"></a><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_23f90d7361a5468995d9a90765d69528-6" name="rest_code_23f90d7361a5468995d9a90765d69528-6" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_23f90d7361a5468995d9a90765d69528-6"></a><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Feature"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_23f90d7361a5468995d9a90765d69528-7" name="rest_code_23f90d7361a5468995d9a90765d69528-7" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_23f90d7361a5468995d9a90765d69528-7"></a><span class="w"> </span><span class="s2">"id"</span><span class="o">:</span><span class="w"> </span><span class="s2">"bar"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_23f90d7361a5468995d9a90765d69528-8" name="rest_code_23f90d7361a5468995d9a90765d69528-8" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_23f90d7361a5468995d9a90765d69528-8"></a><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</pre></div>
<p>and this, where the feature array has been reversed,</p>
<div class="code"><pre class="code javascript"><a id="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-1" name="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-1" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b8c6ad036f1045569e9cb6fed9478fb3-1"></a><span class="p">{</span><span class="w"> </span><span class="s2">"type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"FeatureCollection"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-2" name="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-2" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b8c6ad036f1045569e9cb6fed9478fb3-2"></a><span class="w"> </span><span class="s2">"features"</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="w"></span>
<a id="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-3" name="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-3" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b8c6ad036f1045569e9cb6fed9478fb3-3"></a><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Feature"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-4" name="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-4" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b8c6ad036f1045569e9cb6fed9478fb3-4"></a><span class="w"> </span><span class="s2">"id"</span><span class="o">:</span><span class="w"> </span><span class="s2">"bar"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-5" name="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-5" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b8c6ad036f1045569e9cb6fed9478fb3-5"></a><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-6" name="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-6" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b8c6ad036f1045569e9cb6fed9478fb3-6"></a><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Feature"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-7" name="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-7" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b8c6ad036f1045569e9cb6fed9478fb3-7"></a><span class="w"> </span><span class="s2">"id"</span><span class="o">:</span><span class="w"> </span><span class="s2">"foo"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-8" name="rest_code_b8c6ad036f1045569e9cb6fed9478fb3-8" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b8c6ad036f1045569e9cb6fed9478fb3-8"></a><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</pre></div>
<p>be expected? Strictly speaking, no, because in JSON (see <a class="reference external" href="http://www.json.org">json.org</a> or <a class="reference external" href="http://www.ecma-international.org/publications/standards/Ecma-404.htm">ECMA 404</a>)</p>
<blockquote>
<p>An array is an ordered collection of values.</p>
</blockquote>
<p>whereas</p>
<blockquote>
<p>An object is an unordered set of name/value pairs.</p>
</blockquote>
<p>My question is related to <a class="reference external" href="http://www.ietf.org/mail-archive/web/apps-discuss/current/msg08749.html">one asked on the IETF's apps-discuss
list</a> in
January. Should we expect to be able to patch GeoJSON documents using the ids
of individual features? Being able to do so is more or less the reason why
GeoJSON Features have unique ids, but it's clear to me that a generic RFC 6902
won't do. As James Snell points out in that thread, more expressive paths will
be required.</p>
<p>In my previous post on this topic (see link at the top of this one) I looked at
the addition of a new feature to the tail of the features array. The JSON patch
in this case was very simple. But what if that feature had been inserted at the
head of the features array? Is the resulting patch going to be something that
reads like "push back existing items and add new item to the head?" The result
from python-json-patch isn't pretty.</p>
<div class="code"><pre class="code javascript"><a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-1" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-1" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-1"></a><span class="p">[</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-2" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-2" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-2"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-3" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-3" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-3"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/0/geometry/coordinates/0"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-4" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-4" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-4"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="o">-</span><span class="mf">122.65496134757996</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-5" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-5" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-5"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"replace"</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-6" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-6" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-6"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-7" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-7" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-7"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-8" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-8" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-8"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/0/geometry/coordinates/1"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-9" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-9" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-9"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="mf">45.5212590460849</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-10" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-10" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-10"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"replace"</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-11" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-11" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-11"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-12" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-12" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-12"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-13" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-13" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-13"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/0/properties/Notes"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-14" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-14" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-14"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"remove"</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-15" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-15" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-15"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-16" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-16" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-16"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-17" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-17" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-17"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/0/properties/Name"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-18" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-18" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-18"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Three Friends Coffeehouse"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-19" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-19" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-19"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"replace"</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-20" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-20" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-20"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-21" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-21" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-21"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-22" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-22" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-22"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/0/properties/Address"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-23" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-23" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-23"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="s2">"201 SE 12th Ave, Portland, OR 97214"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-24" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-24" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-24"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"replace"</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-25" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-25" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-25"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-26" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-26" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-26"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-27" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-27" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-27"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/1/geometry/coordinates/0"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-28" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-28" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-28"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="o">-</span><span class="mf">122.67516911029816</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-29" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-29" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-29"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"replace"</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-30" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-30" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-30"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-31" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-31" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-31"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-32" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-32" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-32"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/1/geometry/coordinates/1"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-33" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-33" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-33"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="mf">45.55673233031101</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-34" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-34" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-34"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"replace"</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-35" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-35" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-35"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-36" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-36" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-36"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-37" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-37" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-37"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/1/properties/Notes"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-38" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-38" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-38"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="s2">"usually busy, outlets on side wall only"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-39" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-39" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-39"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"replace"</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-40" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-40" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-40"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-41" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-41" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-41"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-42" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-42" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-42"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/1/properties/Name"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-43" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-43" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-43"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Albina Press"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-44" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-44" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-44"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"replace"</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-45" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-45" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-45"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-46" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-46" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-46"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-47" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-47" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-47"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/1/properties/Address"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-48" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-48" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-48"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="s2">"4637 N Albina Ave Portland, OR 97217"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-49" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-49" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-49"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"replace"</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-50" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-50" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-50"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-51" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-51" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-51"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-52" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-52" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-52"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/2"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-53" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-53" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-53"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-54" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-54" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-54"></a><span class="w"> </span><span class="s2">"geometry"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-55" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-55" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-55"></a><span class="w"> </span><span class="s2">"type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Point"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-56" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-56" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-56"></a><span class="w"> </span><span class="s2">"coordinates"</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-57" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-57" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-57"></a><span class="w"> </span><span class="o">-</span><span class="mf">122.68242716789246</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-58" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-58" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-58"></a><span class="w"> </span><span class="mf">45.56997505986905</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-59" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-59" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-59"></a><span class="w"> </span><span class="p">]</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-60" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-60" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-60"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-61" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-61" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-61"></a><span class="w"> </span><span class="s2">"type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Feature"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-62" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-62" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-62"></a><span class="w"> </span><span class="s2">"properties"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-63" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-63" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-63"></a><span class="w"> </span><span class="s2">"Notes"</span><span class="o">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-64" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-64" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-64"></a><span class="w"> </span><span class="s2">"Name"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Arbor Lodge"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-65" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-65" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-65"></a><span class="w"> </span><span class="s2">"Address"</span><span class="o">:</span><span class="w"> </span><span class="s2">"1507 N Rosa Parks Way Portland, OR 97217"</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-66" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-66" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-66"></a><span class="w"> </span><span class="p">}</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-67" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-67" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-67"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-68" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-68" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-68"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"add"</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-69" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-69" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-69"></a><span class="w"> </span><span class="p">}</span><span class="w"></span>
<a id="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-70" name="rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-70" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_b2f2ef2f978e420a896b9d786d3a5e7f-70"></a><span class="p">]</span><span class="w"></span>
</pre></div>
<p>Unless I misunderstand RFC 6901 and RFC 6902, the following ought to be
possible.</p>
<div class="code"><pre class="code javascript"><a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-1" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-1" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-1"></a><span class="p">[</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-2" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-2" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-2"></a><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"move"</span><span class="p">,</span><span class="w"> </span><span class="s2">"from"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/foo/1"</span><span class="p">,</span><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/foo/2"</span><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-3" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-3" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-3"></a><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"move"</span><span class="p">,</span><span class="w"> </span><span class="s2">"from"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/foo/0"</span><span class="p">,</span><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/foo/1"</span><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-4" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-4" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-4"></a><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/0`"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-5" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-5" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-5"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-6" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-6" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-6"></a><span class="w"> </span><span class="s2">"geometry"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-7" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-7" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-7"></a><span class="w"> </span><span class="s2">"type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Point"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-8" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-8" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-8"></a><span class="w"> </span><span class="s2">"coordinates"</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-9" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-9" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-9"></a><span class="w"> </span><span class="o">-</span><span class="mf">122.65496134757996</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-10" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-10" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-10"></a><span class="w"> </span><span class="mf">45.5212590460849</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-11" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-11" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-11"></a><span class="w"> </span><span class="p">]</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-12" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-12" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-12"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-13" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-13" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-13"></a><span class="w"> </span><span class="s2">"type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Feature"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-14" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-14" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-14"></a><span class="w"> </span><span class="s2">"properties"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-15" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-15" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-15"></a><span class="w"> </span><span class="s2">"Name"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Three Friends Coffeehouse"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-16" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-16" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-16"></a><span class="w"> </span><span class="s2">"Address"</span><span class="o">:</span><span class="w"> </span><span class="s2">"201 SE 12th Ave, Portland, OR 97214"</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-17" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-17" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-17"></a><span class="w"> </span><span class="p">}</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-18" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-18" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-18"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-19" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-19" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-19"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"add"</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<a id="rest_code_99f85a7e6fe446b289cd84b5fa01470c-20" name="rest_code_99f85a7e6fe446b289cd84b5fa01470c-20" href="https://sgillies.net/2013/12/06/some-consequences-of-geojson-features-as-arrays.html#rest_code_99f85a7e6fe446b289cd84b5fa01470c-20"></a><span class="p">]</span><span class="w"></span>
</pre></div>
<p>Making concise patches won't be trivial, that seems clear, and the ideal patch
style for GeoJSON could differ from the ideal style for other applications.
I'm certain that we'd need to get to patches like the latter to make GeoJSON
patching something that developers would consider adopting. JSON PATCH provides
a useful grammar but by itself isn't enough. There's more work to be done.</p>
<p>Did we ever consider making FeatureCollection's features key have an object
value? I'll look in the GeoJSON list archive when I have time.</p>JSON diff and patch for GeoJSONhttps://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html2013-12-04T00:00:00-07:002013-12-04T00:00:00-07:00Sean Gillies<p>We diff and patch source code all the time, but doing the same thing for JSON
data isn't as straightforward. More often than seeing the differences between JSON texts, we're interested in seeing (and sharing
and reapplying) the differences between the objects encoded in the text. We
want to gloss over differences in whitespace and order of object members and
see the real difference in the data. Unix patch and diff operate only on text,
and best on text of consistent and short line length, and aren't very useful
for parsing out differences between objects encoded in JSON. If diff and patch
aren't going to work, what will?</p>
<p>RFC 6902, <a class="reference external" href="http://tools.ietf.org/html/rfc6902">JavaScript Object Notation (JSON) Patch</a> is one attempt at standardizing JSON
patches. From the introduction:</p>
<blockquote>
<p>JavaScript Object Notation (JSON) [<a class="reference external" href="http://tools.ietf.org/html/rfc4627">RFC4627</a>] is a common format for
the exchange and storage of structured data. HTTP PATCH [<a class="reference external" href="http://tools.ietf.org/html/rfc5789">RFC5789</a>]
extends the Hypertext Transfer Protocol (HTTP) [<a class="reference external" href="http://tools.ietf.org/html/rfc2616">RFC2616</a>] with a
method to perform partial modifications to resources.</p>
<p>JSON Patch is a format (identified by the media type "application/
json-patch+json") for expressing a sequence of operations to apply to
a target JSON document; it is suitable for use with the HTTP PATCH
method.</p>
<p>This format is also potentially useful in other cases in which it is
necessary to make partial updates to a JSON document or to a data
structure that has similar constraints (i.e., they can be serialized
as an object or an array using the JSON grammar).</p>
</blockquote>
<p>RFC 6902 comes from developers interested in REST-style interaction with
JSON representations of resources but might be more generally useful. How does
it work? If you're familiar with XPath and XPointer, you might see some
similarities. A JSON patch doc contains an array of path, value, and operation
tuples. The path tells you how to traverse into the JSON document and the
operations specify what is done to objects using the values.</p>
<p>For an example, I'm going to take GeoJSON from Lyzi Diamond's <a class="reference external" href="https://github.com/lyzidiamond/learn-geojson">Learn GeoJSON</a> project and make diffs using
Stefan Kögl's <a class="reference external" href="https://github.com/stefankoegl/python-json-patch">python-json-patch</a> package. RFC 6902 has
implementations in other languages, too, such as <a class="reference external" href="https://github.com/bruth/jsonpatch-js">jsonpatch-js</a> (npm).</p>
<p>Here's a <a class="reference external" href="https://gist.github.com/sgillies/7797688#file-json-diff-py">script</a> that prints out the RFC 6902 diff between commits <a class="reference external" href="https://github.com/lyzidiamond/learn-geojson/blob/44de76ef53b20bdaf51e0cde4aa634df210cd9d4/geojson/hackspots.geojson">44de76ef53</a>
and <a class="reference external" href="https://github.com/lyzidiamond/learn-geojson/blob/e9514f5c317ee980b94ed6580950cfd9fbde53db/geojson/hackspots.geojson">e9514f5c31</a>
of <a class="reference external" href="https://github.com/lyzidiamond/learn-geojson/blob/master/geojson/hackspots.geojson">hackspots.geojson</a>:</p>
<div class="code"><pre class="code python"><a id="rest_code_82d3a6bb16844e1d96947632f48c611f-1" name="rest_code_82d3a6bb16844e1d96947632f48c611f-1" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-1"></a><span class="kn">import</span> <span class="nn">json</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-2" name="rest_code_82d3a6bb16844e1d96947632f48c611f-2" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-2"></a><span class="kn">import</span> <span class="nn">jsonpatch</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-3" name="rest_code_82d3a6bb16844e1d96947632f48c611f-3" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-3"></a><span class="kn">import</span> <span class="nn">os.path</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-4" name="rest_code_82d3a6bb16844e1d96947632f48c611f-4" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-4"></a><span class="kn">import</span> <span class="nn">requests</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-5" name="rest_code_82d3a6bb16844e1d96947632f48c611f-5" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-5"></a><span class="kn">import</span> <span class="nn">subprocess</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-6" name="rest_code_82d3a6bb16844e1d96947632f48c611f-6" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-6"></a>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-7" name="rest_code_82d3a6bb16844e1d96947632f48c611f-7" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-7"></a><span class="c1"># original</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-8" name="rest_code_82d3a6bb16844e1d96947632f48c611f-8" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-8"></a><span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="s1">'hackspots-44de76ef53.json'</span><span class="p">):</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-9" name="rest_code_82d3a6bb16844e1d96947632f48c611f-9" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-9"></a> <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'https://github.com/lyzidiamond/learn-geojson/raw/44de76ef53b20bdaf51e0cde4aa634df210cd9d4/geojson/hackspots.geojson'</span><span class="p">)</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-10" name="rest_code_82d3a6bb16844e1d96947632f48c611f-10" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-10"></a> <span class="n">data</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="n">content</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-11" name="rest_code_82d3a6bb16844e1d96947632f48c611f-11" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-11"></a> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'hackspots-44de76ef53.json'</span><span class="p">,</span> <span class="s1">'wb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-12" name="rest_code_82d3a6bb16844e1d96947632f48c611f-12" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-12"></a> <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-13" name="rest_code_82d3a6bb16844e1d96947632f48c611f-13" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-13"></a>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-14" name="rest_code_82d3a6bb16844e1d96947632f48c611f-14" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-14"></a><span class="c1"># next commit</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-15" name="rest_code_82d3a6bb16844e1d96947632f48c611f-15" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-15"></a><span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="s1">'hackspots-e9514f5c31.json'</span><span class="p">):</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-16" name="rest_code_82d3a6bb16844e1d96947632f48c611f-16" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-16"></a> <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'https://github.com/lyzidiamond/learn-geojson/raw/e9514f5c317ee980b94ed6580950cfd9fbde53db/geojson/hackspots.geojson'</span><span class="p">)</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-17" name="rest_code_82d3a6bb16844e1d96947632f48c611f-17" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-17"></a> <span class="n">data</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="n">content</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-18" name="rest_code_82d3a6bb16844e1d96947632f48c611f-18" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-18"></a> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'hackspots-e9514f5c31.json'</span><span class="p">,</span> <span class="s1">'wb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-19" name="rest_code_82d3a6bb16844e1d96947632f48c611f-19" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-19"></a> <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-20" name="rest_code_82d3a6bb16844e1d96947632f48c611f-20" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-20"></a>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-21" name="rest_code_82d3a6bb16844e1d96947632f48c611f-21" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-21"></a><span class="n">diff_text</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">check_output</span><span class="p">([</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-22" name="rest_code_82d3a6bb16844e1d96947632f48c611f-22" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-22"></a> <span class="s1">'jsondiff'</span><span class="p">,</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-23" name="rest_code_82d3a6bb16844e1d96947632f48c611f-23" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-23"></a> <span class="s1">'hackspots-44de76ef53.json'</span><span class="p">,</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-24" name="rest_code_82d3a6bb16844e1d96947632f48c611f-24" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-24"></a> <span class="s1">'hackspots-e9514f5c31.json'</span><span class="p">])</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-25" name="rest_code_82d3a6bb16844e1d96947632f48c611f-25" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-25"></a><span class="n">diff</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">diff_text</span><span class="p">)</span>
<a id="rest_code_82d3a6bb16844e1d96947632f48c611f-26" name="rest_code_82d3a6bb16844e1d96947632f48c611f-26" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_82d3a6bb16844e1d96947632f48c611f-26"></a><span class="nb">print</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">diff</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span>
</pre></div>
<p>The result looks, to me, like a very reasonable representation of an operation
that adds one feature to a GeoJSON feature collection.</p>
<div class="code"><pre class="code javascript"><a id="rest_code_5869397c285c43c594898ad326a225f0-1" name="rest_code_5869397c285c43c594898ad326a225f0-1" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-1"></a><span class="p">[</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-2" name="rest_code_5869397c285c43c594898ad326a225f0-2" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-2"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-3" name="rest_code_5869397c285c43c594898ad326a225f0-3" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-3"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/2"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-4" name="rest_code_5869397c285c43c594898ad326a225f0-4" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-4"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-5" name="rest_code_5869397c285c43c594898ad326a225f0-5" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-5"></a><span class="w"> </span><span class="s2">"geometry"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-6" name="rest_code_5869397c285c43c594898ad326a225f0-6" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-6"></a><span class="w"> </span><span class="s2">"type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Point"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-7" name="rest_code_5869397c285c43c594898ad326a225f0-7" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-7"></a><span class="w"> </span><span class="s2">"coordinates"</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-8" name="rest_code_5869397c285c43c594898ad326a225f0-8" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-8"></a><span class="w"> </span><span class="o">-</span><span class="mf">122.65496134757996</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-9" name="rest_code_5869397c285c43c594898ad326a225f0-9" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-9"></a><span class="w"> </span><span class="mf">45.5212590460849</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-10" name="rest_code_5869397c285c43c594898ad326a225f0-10" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-10"></a><span class="w"> </span><span class="p">]</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-11" name="rest_code_5869397c285c43c594898ad326a225f0-11" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-11"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-12" name="rest_code_5869397c285c43c594898ad326a225f0-12" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-12"></a><span class="w"> </span><span class="s2">"type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Feature"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-13" name="rest_code_5869397c285c43c594898ad326a225f0-13" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-13"></a><span class="w"> </span><span class="s2">"properties"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-14" name="rest_code_5869397c285c43c594898ad326a225f0-14" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-14"></a><span class="w"> </span><span class="s2">"Name"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Three Friends Coffeehouse"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-15" name="rest_code_5869397c285c43c594898ad326a225f0-15" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-15"></a><span class="w"> </span><span class="s2">"Address"</span><span class="o">:</span><span class="w"> </span><span class="s2">"201 SE 12th Ave, Portland, OR 97214"</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-16" name="rest_code_5869397c285c43c594898ad326a225f0-16" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-16"></a><span class="w"> </span><span class="p">}</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-17" name="rest_code_5869397c285c43c594898ad326a225f0-17" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-17"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-18" name="rest_code_5869397c285c43c594898ad326a225f0-18" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-18"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"add"</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-19" name="rest_code_5869397c285c43c594898ad326a225f0-19" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-19"></a><span class="w"> </span><span class="p">}</span><span class="w"></span>
<a id="rest_code_5869397c285c43c594898ad326a225f0-20" name="rest_code_5869397c285c43c594898ad326a225f0-20" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_5869397c285c43c594898ad326a225f0-20"></a><span class="p">]</span><span class="w"></span>
</pre></div>
<p>A hypothetical change of this same feature's coordinates from <a class="reference external" href="https://github.com/lyzidiamond/learn-geojson/blob/e9514f5c317ee980b94ed6580950cfd9fbde53db/geojson/hackspots.geojson">e9514f5c31</a>
to <a class="reference external" href="https://gist.github.com/sgillies/7797688#file-foo-geojson">https://gist.github.com/sgillies/7797688#file-foo-geojson</a> looks like this:</p>
<div class="code"><pre class="code javascript"><a id="rest_code_19e83f84d84340ebbc65a8efb0212946-1" name="rest_code_19e83f84d84340ebbc65a8efb0212946-1" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_19e83f84d84340ebbc65a8efb0212946-1"></a><span class="p">[</span><span class="w"></span>
<a id="rest_code_19e83f84d84340ebbc65a8efb0212946-2" name="rest_code_19e83f84d84340ebbc65a8efb0212946-2" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_19e83f84d84340ebbc65a8efb0212946-2"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_19e83f84d84340ebbc65a8efb0212946-3" name="rest_code_19e83f84d84340ebbc65a8efb0212946-3" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_19e83f84d84340ebbc65a8efb0212946-3"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/2/geometry/coordinates/0"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_19e83f84d84340ebbc65a8efb0212946-4" name="rest_code_19e83f84d84340ebbc65a8efb0212946-4" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_19e83f84d84340ebbc65a8efb0212946-4"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="o">-</span><span class="mf">122.655</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_19e83f84d84340ebbc65a8efb0212946-5" name="rest_code_19e83f84d84340ebbc65a8efb0212946-5" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_19e83f84d84340ebbc65a8efb0212946-5"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"replace"</span><span class="w"></span>
<a id="rest_code_19e83f84d84340ebbc65a8efb0212946-6" name="rest_code_19e83f84d84340ebbc65a8efb0212946-6" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_19e83f84d84340ebbc65a8efb0212946-6"></a><span class="w"> </span><span class="p">},</span><span class="w"></span>
<a id="rest_code_19e83f84d84340ebbc65a8efb0212946-7" name="rest_code_19e83f84d84340ebbc65a8efb0212946-7" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_19e83f84d84340ebbc65a8efb0212946-7"></a><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_19e83f84d84340ebbc65a8efb0212946-8" name="rest_code_19e83f84d84340ebbc65a8efb0212946-8" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_19e83f84d84340ebbc65a8efb0212946-8"></a><span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/features/2/geometry/coordinates/1"</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_19e83f84d84340ebbc65a8efb0212946-9" name="rest_code_19e83f84d84340ebbc65a8efb0212946-9" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_19e83f84d84340ebbc65a8efb0212946-9"></a><span class="w"> </span><span class="s2">"value"</span><span class="o">:</span><span class="w"> </span><span class="mf">45.522</span><span class="p">,</span><span class="w"></span>
<a id="rest_code_19e83f84d84340ebbc65a8efb0212946-10" name="rest_code_19e83f84d84340ebbc65a8efb0212946-10" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_19e83f84d84340ebbc65a8efb0212946-10"></a><span class="w"> </span><span class="s2">"op"</span><span class="o">:</span><span class="w"> </span><span class="s2">"replace"</span><span class="w"></span>
<a id="rest_code_19e83f84d84340ebbc65a8efb0212946-11" name="rest_code_19e83f84d84340ebbc65a8efb0212946-11" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_19e83f84d84340ebbc65a8efb0212946-11"></a><span class="w"> </span><span class="p">}</span><span class="w"></span>
<a id="rest_code_19e83f84d84340ebbc65a8efb0212946-12" name="rest_code_19e83f84d84340ebbc65a8efb0212946-12" href="https://sgillies.net/2013/12/04/json-diff-and-patch-for-geojson.html#rest_code_19e83f84d84340ebbc65a8efb0212946-12"></a><span class="p">]</span><span class="w"></span>
</pre></div>
<p>There's a potential for RFC 6902 style GeoJSON diffs to become very large if
highly detailed lines and polygons are being modified (via simplication or
reprojection). But GeoJSON itself is quite verbose already and a verbose patch
representation feels not surprising. If you already think GeoJSON sucks, JSON
patch for GeoJSON is going to look exta sucky because of the lengths of paths
to individual coordinate items. I don't think there's any way around that,
although GeoJSON's recursive coordinates member helps a little – consider that
the path to the first 'x' coordinate of the exterior ring of the first part of
a multi-polygon is "just" '/features/42/geometry/coordinates/0/0/0/0'.</p>
<p>I'm not sure how RFC 6902 patches will play out at scale, but I think it's
worth further consideration.</p>Linking GeoJSONhttps://sgillies.net/2013/10/08/linking-geojson.html2013-10-08T00:00:00-06:002013-10-08T00:00:00-06:00Sean Gillies<p>I've blogged a few times (
<a class="reference external" href="http://sgillies.net/blog/888/openlayers-constrained-by-hypertext/">here</a>
and <a class="reference external" href="http://sgillies.net/blog/958/geojson-data-uris/">here</a>) about a pattern
I've developed for mapping feature data associated with a web page.
Lyzi Diamond wrote a great post about this pattern a few weeks ago:
<a class="reference external" href="http://lyzidiamond.com/posts/osgeo-august-meeting/">http://lyzidiamond.com/posts/osgeo-august-meeting/</a>. I'm thrilled that it's
catching on a bit. The pattern is super simple, only three short paragraphs are
needed to describe it.</p>
<p>Let's say I have a collection of web pages. Each is about a particular batch of
features. <a class="reference external" href="http://sgillies.github.io/syriaca/">http://sgillies.github.io/syriaca/</a>, for example, is a demo of a page
about Syriac places in antiquity. It bears a map in which the places are
rendered.</p>
<p>The features to be rendered in the map are obtained by making an HTTP request
for a GeoJSON resource. In my case
<a class="reference external" href="http://sgillies.github.io/syriaca/syriaca.json">http://sgillies.github.io/syriaca/syriaca.json</a> is fetched using
jQuery.getJSON().</p>
<div class="code"><pre class="code javascript"><a id="rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-1" name="rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-1" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-1"></a><span class="kd">var</span><span class="w"> </span><span class="nx">map</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="s1">'map'</span><span class="p">);</span><span class="w"></span>
<a id="rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-2" name="rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-2" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-2"></a><span class="kd">var</span><span class="w"> </span><span class="nx">geojson</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">geoJson</span><span class="p">().</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">map</span><span class="p">);</span><span class="w"></span>
<a id="rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-3" name="rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-3" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-3"></a>
<a id="rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-4" name="rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-4" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-4"></a><span class="nx">$</span><span class="p">.</span><span class="nx">getJSON</span><span class="p">(</span><span class="nx">geojson_uri</span><span class="p">,</span><span class="w"> </span><span class="kd">function</span><span class="w"> </span><span class="p">(</span><span class="nx">data</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<a id="rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-5" name="rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-5" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-5"></a><span class="w"> </span><span class="nx">geojson</span><span class="p">.</span><span class="nx">addData</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span><span class="w"></span>
<a id="rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-6" name="rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-6" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_600b65a00e3b4d6ea3aaa0f44c23e564-6"></a><span class="p">});</span><span class="w"></span>
</pre></div>
<p>The feature data is not written into a script in the page as
they are in <a class="reference external" href="http://leafletjs.com/examples/quick-start-example.html">http://leafletjs.com/examples/quick-start-example.html</a>. Yes,
this means an extra HTTP request, but one that can be ansynchronous and
cacheable.</p>
<p>Here's the crux of the pattern: the URI of that GeoJSON resource bound to the
geojson_uri variable is specified not in the map script, but in a link in the
head of the page.</p>
<div class="code"><pre class="code html"><a id="rest_code_74570743e1b34efe99deca20b9ea062b-1" name="rest_code_74570743e1b34efe99deca20b9ea062b-1" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_74570743e1b34efe99deca20b9ea062b-1"></a><span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"location"</span> <span class="na">type</span><span class="o">=</span><span class="s">"application/json"</span> <span class="na">href</span><span class="o">=</span><span class="s">"syriaca.json"</span><span class="p">/></span>
</pre></div>
<p>That URI is found by its "location" relation type.</p>
<div class="code"><pre class="code javascript"><a id="rest_code_84a4e6986b0c4611a8f4a527aeebc8e6-1" name="rest_code_84a4e6986b0c4611a8f4a527aeebc8e6-1" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_84a4e6986b0c4611a8f4a527aeebc8e6-1"></a><span class="kd">var</span><span class="w"> </span><span class="nx">geojson_uri</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">$</span><span class="p">(</span><span class="s1">'link[rel="location"]'</span><span class="p">).</span><span class="nx">attr</span><span class="p">(</span><span class="s2">"href"</span><span class="p">);</span><span class="w"></span>
</pre></div>
<p>What's gained by having my Javascript follow a link to get GeoJSON features?
Why not just write the features into a script? I've developed this pattern
because it decouples the map from the data and lets me generalize the mapping
script so I can reuse it across many pages, and also because I'm not thinking
just about the slippy maps in the page. I'm keeping the bigger web in mind.</p>
<p>If the Javascript in my page was my only consideration I'd just embed the
features in a script and maybe not use GeoJSON at all. But a resource like
<a class="reference external" href="http://sgillies.github.io/syriaca/">http://sgillies.github.io/syriaca/</a> isn't just a page with a slippy map, it's
a starting point for other web map making software. The links are also for web
clients written by people other than me.</p>
<p>Given the page's URL, a Python web client can get the same GeoJSON in the
same way.</p>
<div class="code"><pre class="code python"><a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-1" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-1" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-1"></a><span class="kn">from</span> <span class="nn">bs4</span> <span class="kn">import</span> <span class="n">BeautifulSoup</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-2" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-2" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-2"></a><span class="kn">import</span> <span class="nn">requests</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-3" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-3" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-3"></a>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-4" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-4" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-4"></a><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'http://sgillies.github.io/syriaca/'</span><span class="p">)</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-5" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-5" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-5"></a><span class="n">soup</span> <span class="o">=</span> <span class="n">BeautifulSoup</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">content</span><span class="p">)</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-6" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-6" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-6"></a><span class="n">points</span> <span class="o">=</span> <span class="p">[</span><span class="n">t</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">soup</span><span class="o">.</span><span class="n">find_all</span><span class="p">(</span><span class="s1">'link'</span><span class="p">)</span> <span class="k">if</span> <span class="s1">'location'</span> <span class="ow">in</span> <span class="n">t</span><span class="p">[</span><span class="s1">'rel'</span><span class="p">]]</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-7" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-7" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-7"></a><span class="nb">print</span> <span class="n">points</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-8" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-8" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-8"></a>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-9" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-9" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-9"></a><span class="c1"># Output:</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-10" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-10" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-10"></a><span class="c1"># [<link href="http://sgillies.github.io/syriaca/syriaca.json" rel="location"/>]</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-11" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-11" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-11"></a>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-12" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-12" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-12"></a><span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">points</span><span class="p">:</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-13" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-13" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-13"></a> <span class="n">s</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">url</span> <span class="o">+</span> <span class="n">p</span><span class="p">[</span><span class="s1">'href'</span><span class="p">])</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-14" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-14" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-14"></a> <span class="n">json</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-15" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-15" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-15"></a> <span class="nb">print</span> <span class="n">json</span><span class="p">[</span><span class="s1">'type'</span><span class="p">],</span> <span class="nb">len</span><span class="p">(</span><span class="n">json</span><span class="p">[</span><span class="s1">'features'</span><span class="p">])</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-16" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-16" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-16"></a>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-17" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-17" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-17"></a><span class="c1"># Output:</span>
<a id="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-18" name="rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-18" href="https://sgillies.net/2013/10/08/linking-geojson.html#rest_code_fa0c4b50849a43399a7cf1f17cd2be1b-18"></a><span class="c1"># FeatureCollection 955</span>
</pre></div>
<p>The GeoJSON URI is much easier to find in a link by its relation type than
by scraping it from a script (were I to use a literal in my first code
example above instead of a geojson_uri variable). There's a IETF draft
written by James Snell proposing standardization of the "location" relation:
<a class="reference external" href="http://tools.ietf.org/html/draft-snell-more-link-relations-01">http://tools.ietf.org/html/draft-snell-more-link-relations-01</a>. My pattern
becomes much more useful with such a standard link relation.</p>
<p>Does this pattern avoid the browser's same-origin policy as Lyzi suggests in
<a class="reference external" href="http://lyzidiamond.com/posts/external-geojson-and-leaflet-the-other-way/">http://lyzidiamond.com/posts/external-geojson-and-leaflet-the-other-way/</a>? As
far as I know, links with rel="stylesheet" are the only ones that a browser
fetches unprompted. The GeoJSON fetched by XHR is still subject to same-origin
policy.</p>The right profilehttps://sgillies.net/2012/10/19/the-right-profile.html2012-10-19T00:00:00-06:002012-10-19T00:00:00-06:00Sean Gillies<p>What's the difference between <a class="reference external" href="http://geojson.org">GeoJSON</a> and plain old
<a class="reference external" href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a> JSON? It seems like a naïve
question, but it's actually rather important. GeoJSON data is JSON data,
following all the rules of RFC 4627, but has additional constraints. The most
significant of these are:</p>
<ul class="simple">
<li><p>GeoJSON object must have a 'type' member.</p></li>
<li><p>The value of that member must be one of the following: "Point", "LineString",
"Polygon", "MultiPoint", "MultiLineString", "MultiPolygon",
"GeometryCollection", "Feature", or "FeatureCollection."</p></li>
<li><p>The items of a FeatureCollection will be arrayed in its 'features' member.</p></li>
<li><p>A Feature's representation in mathematical space is expressed in its 'geometry'
member.</p></li>
<li><p>A geometry's coordinate values are arrayed in X (or easting), Y (or northing),
Z order.</p></li>
</ul>
<p>Say you're writing a HTTP client that requests JSON data from a server and
processes it. How does it "know" how to find the features in the data or the
geometries of those features? If there's exactly one server involved and it
provides only GeoJSON data, you can have a coupled, but reliable client-server
system where the way the data is processed depends on the address of the
server. But if there are multiple JSON APIs involved the brittleness of this
kind of system quickly increases. Just having a JSON schema isn't a silver bullet
because schemata aren't standardized in RFC 4627; the question then becomes how
does the client "know" where to find the schema?</p>
<p>I've written before that GeoJSON might need its own media type to be a good
citizen of Formatland, something like <code class="docutils literal">application/vnd.geojson+json</code>. GitHub
(for example) does <a class="reference external" href="http://developer.github.com/v3/media/">this</a>. Lately,
I'm persuaded by people like Mark Nottingham who argue that a flatter space of
fewer media types is <a class="reference external" href="http://www.mnot.net/blog/2012/04/17/profiles">better</a>.
GeoJSON's extra constraints are only about the structure and interpretation of the
data, they don't affect parsing of the data at all. An <code class="docutils literal">application/json</code>
parser need not skip a beat on GeoJSON and a generic <code class="docutils literal">application/json</code>
application can do plenty of shallow processing on it.</p>
<p>The profile concept from <a class="reference external" href="http://tools.ietf.org/html/draft-wilde-profile-link-04">the 'profile' Link Relation Type</a> I-D seems to suit
GeoJSON well and I'm rooting strongly for this draft. If and when it is
finalized, we can declare GeoJSON to be just a profile of <code class="docutils literal">application/json</code>
and clients can use the profile declaration to make more sense of data instead
of out-of-band information or sniffing and guessing.</p>
<p>Profiles could also be a means for making sense of the various profiles of
GeoJSON already found in the wild today. I've come up with a short list of five,
apologies for any omissions.</p>
<p>Microsoft's OData <a class="reference external" href="http://msdn.microsoft.com/en-us/library/hh554611(prot.20).aspx">removes one constraint from GeoJSON and adds two more</a>:</p>
<blockquote>
<p>Any GeoJSON value that is used in OData SHOULD order the keys with type
first, then coordinates, then any other keys. This improves streaming parser
performance when parsing values on open types or in other cases where
metadata is not present.</p>
<p>The GeoJSON [GeoJSON] standard requires that LineString contains a minimum
number of Positions in its coordinates collection. This prevents serializing
certain valid geospatial values. Therefore, in the GeoJSON requirement “For
type ‘LineString’, the ‘coordinates’ member must be an array of two or more
positions” is replaced with the requirement “For type ‘LineString’, the
‘coordinates’ member must be an array of positions” when used in OData.</p>
<p>All other arrays in GeoJSON are allowed to be empty, so no change is
necessary. GeoJSON does require that any LinearRing contain a minimum of four
positions. That requirement still holds that LinearRings can show up only in
other arrays and that those arrays can be empty.</p>
<p>GeoJSON allows multiple types of CRS. In OData, only one of those types is
allowed. In GeoJSON in OData, a CRS MUST be a Named CRS. In addition, OGC CRS
URNs are not supported. The CRS identifier MUST be an EPSG SRID legacy
identifier.</p>
</blockquote>
<p>Madrona's KML-ish <a class="reference external" href="http://ecotrust.github.com/madrona/docs/geojson.html">nested feature collections</a> are another profile.</p>
<p>Leaflet examples, like that for <a class="reference external" href="http://leaflet.cloudmade.com/reference.html#geojson">L.GeoJSON</a>, hint at a profile
where features have 'title' and 'description' properties.</p>
<p>Pleiades has its own profile of GeoJSON in which we add a representative point
member to features, an anchor for labels and popups. The Pleiades profile also
has 'title' and 'description' properties.</p>
<p>The 'geo' member in <a class="reference external" href="https://dev.twitter.com/docs/api/1.1/get/statuses/show/%3Aid">Twitter's 1.1 API</a> uses a
classic profile of GeoJSON, the "surely you mean latitude, longitude order!"
profile.</p>
<p>In anticipation of the 'profile' Link Relation Type I-D getting past the IETF
and IANA hurdles, I've created a strawman proposal for how GeoJSON might use
it: <a class="reference external" href="https://gist.github.com/3853624">https://gist.github.com/3853624</a>. Please check it out, comment, or fork it
if you've got your own profile of GeoJSON and are interested in expressing it
using profile links.</p>Gearing up for LAWDIhttps://sgillies.net/2012/05/15/gearing-up-for-lawdi.html2012-05-15T00:00:00-06:002012-05-15T00:00:00-06:00Sean Gillies<p>I'm beginning to work on my presentation for the upcoming <a class="reference external" href="http://sgillies.net/blog/1116/linked-ancient-world-data-institute/">Linked Ancient World
Data Institute</a> at ISAW. Here's what I'd like to accomplish in three bullets.</p>
<ul class="simple">
<li><p>Engage attendees in thinking outside the database and thinking and talking
about the architecture of the web.</p></li>
<li><p>Make a case for using HTTP URIs (aka URLs) whenever possible instead of other
identifiers or addresses.</p></li>
<li><p>Talk about using links in data for doing work (using verbs) in contrast to
using linked data for reasoning (with nouns).</p></li>
</ul>
<p>How to turn expertly curated non-linked data (digital scholarly editions of
texts, etc) into RDF is one linked data problem, the one we're most familiar
with and most focused on. How to use semantic web architecture and links to
initiate and curate "born-linked" data is another interesting and important set
of problems – to me, at least, and I hope to be able to make it compelling to
everyone else.</p>
<p>Pleiades remains the only classics project in the Linked Open Data cloud today
(<a class="reference external" href="http://thedatahub.org/group/lodcloud?q=classics">http://thedatahub.org/group/lodcloud?q=classics</a>) and I'd also like to talk
about how other projects can join it, but time may be too short for this.</p>RFC 5988https://sgillies.net/2010/10/31/rfc-5988.html2010-10-31T00:00:00-06:002010-10-31T00:00:00-06:00Sean Gillies<p>Web Linking is <a class="reference external" href="http://tools.ietf.org/html/rfc5988">RFC 5988</a>. Via Assaf Arkin's <a class="reference external" href="http://labnotes.org/2010/10/30/rounded-corners-258-%e2%80%94-taco-bell/">Rounded Corners 258</a> I came on to an example (for Firefox and Opera) that assigns a stylesheet using <a class="reference external" href="http://playground.deaxon.com/css/http-headers-styles/">.htaccess</a>. This could also be used to turn "dumb" image files into hypermedia; a map tile JPEG could link (in its headers) to metadata, to neighboring tiles, to data for the features depicted within.</p>
<p><strong>Update</strong> (2010-11-04): <a class="reference external" href="http://dret.typepad.com/dretblog/2010/11/web-linking.html">more</a> from Erik Wilde.</p>GDAL Web driverhttps://sgillies.net/2010/10/04/gdal-web-driver.html2010-10-04T00:00:00-06:002010-10-04T00:00:00-06:00Sean Gillies<p>Network file systems or web services got you down? Sidestep them with a lightweight and high
performance <a class="reference external" href="http://crschmidt.net/blog/archives/425/vsi-curl-support/">GDAL filesystem implemented on HTTP</a>:</p>
<blockquote>
<p>People sometimes talk about “RESTful” services on the web, and I’ll admit
that there’s a lot to that that I don’t really understand. I’ll admit that
the tiff format is not designed to have HTTP ‘links’ to each pixel — but I
think the fact that by fetching a small set of header information, GDAL is
then able to find out where the metadata is, and request only that data,
saving (in this case) more than a gigabyte of network bandwidth… that’s
pretty frickin’ cool.</p>
</blockquote>
<p>Part of what makes this work is the Web's built-in support for byte range requests and partial representations. See RFC 2616 section <a class="reference external" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35">14.35.1</a> and HTTPbis <a class="reference external" href="http://tools.ietf.org/html/draft-ietf-httpbis-p5-range-11">part 5</a>:</p>
<blockquote>
<p>Since all HTTP entities are represented in HTTP messages as sequences of
bytes, the concept of a byte range is meaningful for any HTTP entity.</p>
</blockquote>
<p>Make a small byte range request for TIFF metadata so you can map pixel and row
(and maybe pyramid depth) to an entity byte range and then request just the
right subset of the image.</p>
<p>For what it's worth, there's a W3C <a class="reference external" href="http://www.w3.org/2008/WebVideo/Fragments/">Media Fragments Working Group</a> with a
mission of making image subsets more <a class="reference external" href="http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/">addressable</a>.</p>
<section id="comments">
<h2>Comments</h2>
<section id="re-gdal-web-driver">
<h3>Re: GDAL Web driver</h3>
<p>Author: <a class="reference external" href="http://crschmidt.net/">Christopher Schmidt</a></p>
<p>Hey, I recognize some of that text.</p><p></p><p>I'm not really sure how your second quote addresses my actual "I don't understand" section (which is terribly worded, bad on me for writing under the influence of sudafed). The HTTP spec surely describes byte ranges as meaningful, but does that mean that accessing things via byte ranges is RESTful?</p></section>
<section id="re-gdal-web-driver-1">
<h3>Re: GDAL Web driver</h3>
<p>Author: Sean</p>
<p>I should edit my post to make it clear that the second quote isn't meant to be a rebuttal or counterpoint to your first one. Partial representations aren't part of "textbook" REST, but aren't inconsistent with it.</p></section>
</section>