1 /******************************************************************************
2 * $Id: ogrgeojsonreader.cpp 29156 2015-05-05 10:19:17Z rouault $
3 *
4 * Project: OpenGIS Simple Features Reference Implementation
5 * Purpose: Implementation of OGRGeoJSONReader class (OGR GeoJSON Driver).
6 * Author: Mateusz Loskot, mateusz@loskot.net
7 *
8 ******************************************************************************
9 * Copyright (c) 2007, Mateusz Loskot
10 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at mines-paris dot org>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30 #include "ogrgeojsonreader.h"
31 #include "ogrgeojsonutils.h"
32 #include "ogr_geojson.h"
33 #include <json.h> // JSON-C
34 #include <ogr_api.h>
35
36 /************************************************************************/
37 /* OGRGeoJSONReader */
38 /************************************************************************/
39
OGRGeoJSONReader()40 OGRGeoJSONReader::OGRGeoJSONReader()
41 : poGJObject_( NULL ),
42 bGeometryPreserve_( true ),
43 bAttributesSkip_( false ),
44 bFlattenNestedAttributes_ (false),
45 chNestedAttributeSeparator_ (0),
46 bFlattenGeocouchSpatiallistFormat (-1), bFoundId (false), bFoundRev(false), bFoundTypeFeature(false), bIsGeocouchSpatiallistFormat(false)
47 {
48 // Take a deep breath and get to work.
49 }
50
51 /************************************************************************/
52 /* ~OGRGeoJSONReader */
53 /************************************************************************/
54
~OGRGeoJSONReader()55 OGRGeoJSONReader::~OGRGeoJSONReader()
56 {
57 if( NULL != poGJObject_ )
58 {
59 json_object_put(poGJObject_);
60 }
61
62 poGJObject_ = NULL;
63 }
64
65 /************************************************************************/
66 /* Parse */
67 /************************************************************************/
68
Parse(const char * pszText)69 OGRErr OGRGeoJSONReader::Parse( const char* pszText )
70 {
71 if( NULL != pszText )
72 {
73 json_tokener* jstok = NULL;
74 json_object* jsobj = NULL;
75
76 /* Skip UTF-8 BOM (#5630) */
77 const GByte* pabyData = (const GByte*)pszText;
78 if( pabyData[0] == 0xEF && pabyData[1] == 0xBB && pabyData[2] == 0xBF )
79 {
80 CPLDebug("GeoJSON", "Skip UTF-8 BOM");
81 pszText += 3;
82 }
83
84 jstok = json_tokener_new();
85 jsobj = json_tokener_parse_ex(jstok, pszText, -1);
86 if( jstok->err != json_tokener_success)
87 {
88 CPLError( CE_Failure, CPLE_AppDefined,
89 "GeoJSON parsing error: %s (at offset %d)",
90 json_tokener_error_desc(jstok->err), jstok->char_offset);
91
92 json_tokener_free(jstok);
93 return OGRERR_CORRUPT_DATA;
94 }
95 json_tokener_free(jstok);
96
97 /* JSON tree is shared for while lifetime of the reader object
98 * and will be released in the destructor.
99 */
100 poGJObject_ = jsobj;
101 }
102
103 return OGRERR_NONE;
104 }
105
106 /************************************************************************/
107 /* ReadLayers */
108 /************************************************************************/
109
ReadLayers(OGRGeoJSONDataSource * poDS)110 void OGRGeoJSONReader::ReadLayers( OGRGeoJSONDataSource* poDS )
111 {
112 if( NULL == poGJObject_ )
113 {
114 CPLDebug( "GeoJSON",
115 "Missing parset GeoJSON data. Forgot to call Parse()?" );
116 return;
117 }
118
119 ReadLayer(poDS, OGRGeoJSONLayer::DefaultName, poGJObject_);
120 }
121
122 /************************************************************************/
123 /* ReadLayer */
124 /************************************************************************/
125
ReadLayer(OGRGeoJSONDataSource * poDS,const char * pszName,json_object * poObj)126 void OGRGeoJSONReader::ReadLayer( OGRGeoJSONDataSource* poDS,
127 const char* pszName,
128 json_object* poObj )
129 {
130 GeoJSONObject::Type objType = OGRGeoJSONGetType( poObj );
131 if( objType == GeoJSONObject::eUnknown )
132 {
133 /* Check if the object contains key:value pairs where value */
134 /* is a standard GeoJSON object. In which case, use key as the layer */
135 /* name */
136 if( json_type_object == json_object_get_type( poObj ) )
137 {
138 json_object_iter it;
139 it.key = NULL;
140 it.val = NULL;
141 it.entry = NULL;
142 json_object_object_foreachC( poObj, it )
143 {
144 objType = OGRGeoJSONGetType( it.val );
145 if( objType != GeoJSONObject::eUnknown )
146 ReadLayer(poDS, it.key, it.val);
147 }
148 }
149
150 /*CPLError( CE_Failure, CPLE_AppDefined,
151 "Unrecognized GeoJSON structure." );*/
152
153 return;
154 }
155
156 OGRSpatialReference* poSRS = NULL;
157 poSRS = OGRGeoJSONReadSpatialReference( poObj );
158 if (poSRS == NULL ) {
159 // If there is none defined, we use 4326
160 poSRS = new OGRSpatialReference();
161 if( OGRERR_NONE != poSRS->importFromEPSG( 4326 ) )
162 {
163 delete poSRS;
164 poSRS = NULL;
165 }
166 }
167
168 OGRGeoJSONLayer* poLayer = new OGRGeoJSONLayer( pszName, poSRS,
169 OGRGeoJSONLayer::DefaultGeometryType,
170 poDS );
171 if( poSRS != NULL )
172 poSRS->Release();
173
174 if( !GenerateLayerDefn(poLayer, poObj) )
175 {
176 CPLError( CE_Failure, CPLE_AppDefined,
177 "Layer schema generation failed." );
178
179 delete poLayer;
180 return;
181 }
182
183 /* -------------------------------------------------------------------- */
184 /* Translate single geometry-only Feature object. */
185 /* -------------------------------------------------------------------- */
186
187 if( GeoJSONObject::ePoint == objType
188 || GeoJSONObject::eMultiPoint == objType
189 || GeoJSONObject::eLineString == objType
190 || GeoJSONObject::eMultiLineString == objType
191 || GeoJSONObject::ePolygon == objType
192 || GeoJSONObject::eMultiPolygon == objType
193 || GeoJSONObject::eGeometryCollection == objType )
194 {
195 OGRGeometry* poGeometry = NULL;
196 poGeometry = ReadGeometry( poObj );
197 if( !AddFeature( poLayer, poGeometry ) )
198 {
199 CPLDebug( "GeoJSON",
200 "Translation of single geometry failed." );
201 delete poLayer;
202 return;
203 }
204 }
205 /* -------------------------------------------------------------------- */
206 /* Translate single but complete Feature object. */
207 /* -------------------------------------------------------------------- */
208 else if( GeoJSONObject::eFeature == objType )
209 {
210 OGRFeature* poFeature = NULL;
211 poFeature = ReadFeature( poLayer, poObj );
212 if( !AddFeature( poLayer, poFeature ) )
213 {
214 CPLDebug( "GeoJSON",
215 "Translation of single feature failed." );
216
217 delete poLayer;
218 return;
219 }
220 }
221 /* -------------------------------------------------------------------- */
222 /* Translate multi-feature FeatureCollection object. */
223 /* -------------------------------------------------------------------- */
224 else if( GeoJSONObject::eFeatureCollection == objType )
225 {
226 ReadFeatureCollection( poLayer, poObj );
227 }
228
229 CPLErrorReset();
230
231 poDS->AddLayer(poLayer);
232 }
233
234 /************************************************************************/
235 /* OGRGeoJSONReadSpatialReference */
236 /************************************************************************/
237
OGRGeoJSONReadSpatialReference(json_object * poObj)238 OGRSpatialReference* OGRGeoJSONReadSpatialReference( json_object* poObj) {
239
240 /* -------------------------------------------------------------------- */
241 /* Read spatial reference definition. */
242 /* -------------------------------------------------------------------- */
243 OGRSpatialReference* poSRS = NULL;
244
245 json_object* poObjSrs = OGRGeoJSONFindMemberByName( poObj, "crs" );
246 if( NULL != poObjSrs )
247 {
248 json_object* poObjSrsType = OGRGeoJSONFindMemberByName( poObjSrs, "type" );
249 if (poObjSrsType == NULL)
250 return NULL;
251
252 const char* pszSrsType = json_object_get_string( poObjSrsType );
253
254 // TODO: Add URL and URN types support
255 if( EQUALN( pszSrsType, "NAME", 4 ) )
256 {
257 json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
258 if (poObjSrsProps == NULL)
259 return NULL;
260
261 json_object* poNameURL = OGRGeoJSONFindMemberByName( poObjSrsProps, "name" );
262 if (poNameURL == NULL)
263 return NULL;
264
265 const char* pszName = json_object_get_string( poNameURL );
266
267 poSRS = new OGRSpatialReference();
268 if( OGRERR_NONE != poSRS->SetFromUserInput( pszName ) )
269 {
270 delete poSRS;
271 poSRS = NULL;
272 }
273 }
274
275 if( EQUALN( pszSrsType, "EPSG", 4 ) )
276 {
277 json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
278 if (poObjSrsProps == NULL)
279 return NULL;
280
281 json_object* poObjCode = OGRGeoJSONFindMemberByName( poObjSrsProps, "code" );
282 if (poObjCode == NULL)
283 return NULL;
284
285 int nEPSG = json_object_get_int( poObjCode );
286
287 poSRS = new OGRSpatialReference();
288 if( OGRERR_NONE != poSRS->importFromEPSG( nEPSG ) )
289 {
290 delete poSRS;
291 poSRS = NULL;
292 }
293 }
294
295 if( EQUALN( pszSrsType, "URL", 3 ) || EQUALN( pszSrsType, "LINK", 4 ) )
296 {
297 json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
298 if (poObjSrsProps == NULL)
299 return NULL;
300
301 json_object* poObjURL = OGRGeoJSONFindMemberByName( poObjSrsProps, "url" );
302
303 if (NULL == poObjURL) {
304 poObjURL = OGRGeoJSONFindMemberByName( poObjSrsProps, "href" );
305 }
306 if (poObjURL == NULL)
307 return NULL;
308
309 const char* pszURL = json_object_get_string( poObjURL );
310
311 poSRS = new OGRSpatialReference();
312 if( OGRERR_NONE != poSRS->importFromUrl( pszURL ) )
313 {
314 delete poSRS;
315 poSRS = NULL;
316
317 }
318 }
319
320
321 if( EQUAL( pszSrsType, "OGC" ) )
322 {
323 json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
324 if (poObjSrsProps == NULL)
325 return NULL;
326
327 json_object* poObjURN = OGRGeoJSONFindMemberByName( poObjSrsProps, "urn" );
328 if (poObjURN == NULL)
329 return NULL;
330
331 poSRS = new OGRSpatialReference();
332 if( OGRERR_NONE != poSRS->importFromURN( json_object_get_string(poObjURN) ) )
333 {
334 delete poSRS;
335 poSRS = NULL;
336 }
337 }
338 }
339
340 /* Strip AXIS, since geojson has (easting, northing) / (longitude, latitude) order. */
341 /* According to http://www.geojson.org/geojson-spec.html#id2 : "Point coordinates are in x, y order */
342 /* (easting, northing for projected coordinates, longitude, latitude for geographic coordinates)" */
343 if( poSRS != NULL )
344 {
345 OGR_SRSNode *poGEOGCS = poSRS->GetAttrNode( "GEOGCS" );
346 if( poGEOGCS != NULL )
347 poGEOGCS->StripNodes( "AXIS" );
348 }
349
350 return poSRS;
351 }
352 /************************************************************************/
353 /* SetPreserveGeometryType */
354 /************************************************************************/
355
SetPreserveGeometryType(bool bPreserve)356 void OGRGeoJSONReader::SetPreserveGeometryType( bool bPreserve )
357 {
358 bGeometryPreserve_ = bPreserve;
359 }
360
361 /************************************************************************/
362 /* SetSkipAttributes */
363 /************************************************************************/
364
SetSkipAttributes(bool bSkip)365 void OGRGeoJSONReader::SetSkipAttributes( bool bSkip )
366 {
367 bAttributesSkip_ = bSkip;
368 }
369
370 /************************************************************************/
371 /* SetSkipAttributes */
372 /************************************************************************/
373
SetFlattenNestedAttributes(bool bFlatten,char chSeparator)374 void OGRGeoJSONReader::SetFlattenNestedAttributes( bool bFlatten, char chSeparator )
375 {
376 bFlattenNestedAttributes_ = bFlatten;
377 chNestedAttributeSeparator_ = chSeparator;
378 }
379
380 /************************************************************************/
381 /* GenerateLayerDefn() */
382 /************************************************************************/
383
GenerateLayerDefn(OGRGeoJSONLayer * poLayer,json_object * poGJObject)384 bool OGRGeoJSONReader::GenerateLayerDefn( OGRGeoJSONLayer* poLayer, json_object* poGJObject )
385 {
386 CPLAssert( NULL != poGJObject );
387 CPLAssert( NULL != poLayer->GetLayerDefn() );
388 CPLAssert( 0 == poLayer->GetLayerDefn()->GetFieldCount() );
389
390 bool bSuccess = true;
391
392 if( bAttributesSkip_ )
393 return true;
394
395 /* -------------------------------------------------------------------- */
396 /* Scan all features and generate layer definition. */
397 /* -------------------------------------------------------------------- */
398 GeoJSONObject::Type objType = OGRGeoJSONGetType( poGJObject );
399 if( GeoJSONObject::eFeature == objType )
400 {
401 bSuccess = GenerateFeatureDefn( poLayer, poGJObject );
402 }
403 else if( GeoJSONObject::eFeatureCollection == objType )
404 {
405 json_object* poObjFeatures = NULL;
406 poObjFeatures = OGRGeoJSONFindMemberByName( poGJObject, "features" );
407 if( NULL != poObjFeatures
408 && json_type_array == json_object_get_type( poObjFeatures ) )
409 {
410 json_object* poObjFeature = NULL;
411 const int nFeatures = json_object_array_length( poObjFeatures );
412 for( int i = 0; i < nFeatures; ++i )
413 {
414 poObjFeature = json_object_array_get_idx( poObjFeatures, i );
415 if( !GenerateFeatureDefn( poLayer, poObjFeature ) )
416 {
417 CPLDebug( "GeoJSON", "Create feature schema failure." );
418 bSuccess = false;
419 }
420 }
421 }
422 else
423 {
424 CPLError( CE_Failure, CPLE_AppDefined,
425 "Invalid FeatureCollection object. "
426 "Missing \'features\' member." );
427 bSuccess = false;
428 }
429 }
430
431 /* -------------------------------------------------------------------- */
432 /* Validate and add FID column if necessary. */
433 /* -------------------------------------------------------------------- */
434 OGRFeatureDefn* poLayerDefn = poLayer->GetLayerDefn();
435 CPLAssert( NULL != poLayerDefn );
436
437 /* bool bHasFID = false; */
438
439 for( int i = 0; i < poLayerDefn->GetFieldCount(); ++i )
440 {
441 OGRFieldDefn* poDefn = poLayerDefn->GetFieldDefn(i);
442 if( EQUAL( poDefn->GetNameRef(), OGRGeoJSONLayer::DefaultFIDColumn )
443 && (OFTInteger == poDefn->GetType() || OFTInteger64 == poDefn->GetType()) )
444 {
445 poLayer->SetFIDColumn( poDefn->GetNameRef() );
446 /* bHasFID = true; */
447 break;
448 }
449 }
450
451 // TODO - mloskot: This is wrong! We want to add only FID field if
452 // found in source layer (by default name or by FID_PROPERTY= specifier,
453 // the latter has to be implemented).
454 /*
455 if( !bHasFID )
456 {
457 OGRFieldDefn fldDefn( OGRGeoJSONLayer::DefaultFIDColumn, OFTInteger );
458 poLayerDefn->AddFieldDefn( &fldDefn );
459 poLayer_->SetFIDColumn( fldDefn.GetNameRef() );
460 }
461 */
462
463 return bSuccess;
464 }
465
466 /************************************************************************/
467 /* OGRGeoJSONReaderAddNewField() */
468 /************************************************************************/
469
OGRGeoJSONReaderAddOrUpdateField(OGRFeatureDefn * poDefn,const char * pszKey,json_object * poVal,bool bFlattenNestedAttributes,char chNestedAttributeSeparator)470 void OGRGeoJSONReaderAddOrUpdateField(OGRFeatureDefn* poDefn,
471 const char* pszKey,
472 json_object* poVal,
473 bool bFlattenNestedAttributes,
474 char chNestedAttributeSeparator)
475 {
476 if( bFlattenNestedAttributes &&
477 poVal != NULL && json_object_get_type(poVal) == json_type_object )
478 {
479 json_object_iter it;
480 it.key = NULL;
481 it.val = NULL;
482 it.entry = NULL;
483 json_object_object_foreachC( poVal, it )
484 {
485 char szSeparator[2];
486 szSeparator[0] = chNestedAttributeSeparator;
487 szSeparator[1] = 0;
488 CPLString osAttrName(CPLSPrintf("%s%s%s", pszKey, szSeparator,
489 it.key));
490 if( it.val != NULL && json_object_get_type(it.val) == json_type_object )
491 {
492 OGRGeoJSONReaderAddOrUpdateField(poDefn, osAttrName, it.val,
493 TRUE, chNestedAttributeSeparator);
494 }
495 else
496 {
497 OGRGeoJSONReaderAddOrUpdateField(poDefn, osAttrName, it.val, FALSE, 0);
498 }
499 }
500 return;
501 }
502
503 int nIndex = poDefn->GetFieldIndex(pszKey);
504 if( nIndex < 0 )
505 {
506 OGRFieldSubType eSubType;
507 OGRFieldDefn fldDefn( pszKey,
508 GeoJSONPropertyToFieldType( poVal, eSubType ) );
509 fldDefn.SetSubType(eSubType);
510 if( eSubType == OFSTBoolean )
511 fldDefn.SetWidth(1);
512 if( fldDefn.GetType() == OFTString )
513 {
514 fldDefn.SetType(GeoJSONStringPropertyToFieldType( poVal ));
515 }
516 poDefn->AddFieldDefn( &fldDefn );
517 }
518 else
519 {
520 OGRFieldDefn* poFDefn = poDefn->GetFieldDefn(nIndex);
521 OGRFieldType eType = poFDefn->GetType();
522 if( eType == OFTInteger )
523 {
524 OGRFieldSubType eSubType;
525 OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
526 if( eNewType == OFTInteger &&
527 poFDefn->GetSubType() == OFSTBoolean && eSubType != OFSTBoolean )
528 {
529 poFDefn->SetSubType(OFSTNone);
530 }
531 else if( eNewType == OFTInteger64 || eNewType == OFTReal || eNewType == OFTString )
532 {
533 poFDefn->SetType(eNewType);
534 poFDefn->SetSubType(OFSTNone);
535 }
536 }
537 else if( eType == OFTInteger64 )
538 {
539 OGRFieldSubType eSubType;
540 OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
541 if( eNewType == OFTReal || eNewType == OFTString )
542 {
543 poFDefn->SetType(eNewType);
544 poFDefn->SetSubType(OFSTNone);
545 }
546 }
547 else if( eType == OFTIntegerList || eType == OFTInteger64List )
548 {
549 OGRFieldSubType eSubType;
550 OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
551 if( eNewType == OFTInteger64List || eNewType == OFTRealList || eNewType == OFTStringList )
552 poFDefn->SetType(eNewType);
553 }
554 else if( eType == OFTRealList )
555 {
556 OGRFieldSubType eSubType;
557 OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
558 if( eNewType == OFTStringList )
559 poFDefn->SetType(eNewType);
560 }
561 else if( eType == OFTDate || eType == OFTTime || eType == OFTDateTime )
562 {
563 OGRFieldSubType eSubType;
564 OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
565 if( eNewType == OFTString )
566 eNewType = GeoJSONStringPropertyToFieldType( poVal );
567 if( eType != eNewType )
568 {
569 if( eType == OFTDate && eNewType == OFTDateTime )
570 {
571 poFDefn->SetType(OFTDateTime);
572 }
573 else if( !(eType == OFTDateTime && eNewType == OFTDate) )
574 {
575 poFDefn->SetType(OFTString);
576 }
577 }
578 }
579 }
580 }
581
582 /************************************************************************/
583 /* GenerateFeatureDefn() */
584 /************************************************************************/
GenerateFeatureDefn(OGRGeoJSONLayer * poLayer,json_object * poObj)585 bool OGRGeoJSONReader::GenerateFeatureDefn( OGRGeoJSONLayer* poLayer, json_object* poObj )
586 {
587 OGRFeatureDefn* poDefn = poLayer->GetLayerDefn();
588 CPLAssert( NULL != poDefn );
589
590 bool bSuccess = false;
591
592 /* -------------------------------------------------------------------- */
593 /* Read collection of properties. */
594 /* -------------------------------------------------------------------- */
595 json_object* poObjProps = NULL;
596 poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
597
598 // If there's a top-level id of type string, and no properties.id, then
599 // declare a id field
600 if( poDefn->GetFieldIndex( "id" ) < 0 )
601 {
602 json_object* poObjId = OGRGeoJSONFindMemberByName( poObj, "id" );
603 if( poObjId && json_object_get_type(poObjId) == json_type_string )
604 {
605 int bHasRegularIdProp = FALSE;
606 if( NULL != poObjProps &&
607 json_object_get_type(poObjProps) == json_type_object )
608 {
609 bHasRegularIdProp = (json_object_object_get(poObjProps, "id") != NULL);
610 }
611 if( !bHasRegularIdProp )
612 {
613 OGRFieldDefn fldDefn( "id", OFTString );
614 poDefn->AddFieldDefn(&fldDefn);
615 }
616 }
617 }
618
619 if( NULL != poObjProps &&
620 json_object_get_type(poObjProps) == json_type_object )
621 {
622 if (bIsGeocouchSpatiallistFormat)
623 {
624 poObjProps = json_object_object_get(poObjProps, "properties");
625 if( NULL == poObjProps ||
626 json_object_get_type(poObjProps) != json_type_object )
627 {
628 return true;
629 }
630 }
631
632 json_object_iter it;
633 it.key = NULL;
634 it.val = NULL;
635 it.entry = NULL;
636 json_object_object_foreachC( poObjProps, it )
637 {
638 int nFldIndex = poDefn->GetFieldIndex( it.key );
639 if( -1 == nFldIndex )
640 {
641 /* Detect the special kind of GeoJSON output by a spatiallist of GeoCouch */
642 /* such as http://gd.iriscouch.com/cphosm/_design/geo/_rewrite/data?bbox=12.53%2C55.73%2C12.54%2C55.73 */
643 if (strcmp(it.key, "_id") == 0)
644 bFoundId = true;
645 else if (bFoundId && strcmp(it.key, "_rev") == 0)
646 bFoundRev = true;
647 else if (bFoundRev && strcmp(it.key, "type") == 0 &&
648 it.val != NULL && json_object_get_type(it.val) == json_type_string &&
649 strcmp(json_object_get_string(it.val), "Feature") == 0)
650 bFoundTypeFeature = true;
651 else if (bFoundTypeFeature && strcmp(it.key, "properties") == 0 &&
652 it.val != NULL && json_object_get_type(it.val) == json_type_object)
653 {
654 if (bFlattenGeocouchSpatiallistFormat < 0)
655 bFlattenGeocouchSpatiallistFormat = CSLTestBoolean(
656 CPLGetConfigOption("GEOJSON_FLATTEN_GEOCOUCH", "TRUE"));
657 if (bFlattenGeocouchSpatiallistFormat)
658 {
659 poDefn->DeleteFieldDefn(poDefn->GetFieldIndex("type"));
660 bIsGeocouchSpatiallistFormat = true;
661 return GenerateFeatureDefn(poLayer, poObj);
662 }
663 }
664
665 }
666 OGRGeoJSONReaderAddOrUpdateField(poDefn, it.key, it.val,
667 bFlattenNestedAttributes_,
668 chNestedAttributeSeparator_);
669 }
670
671 bSuccess = true; // SUCCESS
672 }
673 else
674 {
675 json_object_iter it;
676 it.key = NULL;
677 it.val = NULL;
678 it.entry = NULL;
679 json_object_object_foreachC( poObj, it )
680 {
681 if( strcmp(it.key, "type") != 0 &&
682 strcmp(it.key, "geometry") != 0 &&
683 strcmp(it.key, "centroid") != 0 &&
684 strcmp(it.key, "bbox") != 0 &&
685 strcmp(it.key, "center") != 0 )
686 {
687 int nFldIndex = poDefn->GetFieldIndex( it.key );
688 if( -1 == nFldIndex )
689 {
690 OGRFieldDefn fldDefn( it.key, OFTString );
691 poDefn->AddFieldDefn( &fldDefn );
692 }
693 }
694 }
695
696 bSuccess = true; // SUCCESS
697 /*CPLError( CE_Failure, CPLE_AppDefined,
698 "Invalid Feature object. "
699 "Missing \'properties\' member." );*/
700 }
701
702 return bSuccess;
703 }
704
705 /************************************************************************/
706 /* AddFeature */
707 /************************************************************************/
708
AddFeature(OGRGeoJSONLayer * poLayer,OGRGeometry * poGeometry)709 bool OGRGeoJSONReader::AddFeature( OGRGeoJSONLayer* poLayer, OGRGeometry* poGeometry )
710 {
711 bool bAdded = false;
712
713 // TODO: Should we check if geometry is of type of
714 // wkbGeometryCollection ?
715
716 if( NULL != poGeometry )
717 {
718 OGRFeature* poFeature = NULL;
719 poFeature = new OGRFeature( poLayer->GetLayerDefn() );
720 poFeature->SetGeometryDirectly( poGeometry );
721
722 bAdded = AddFeature( poLayer, poFeature );
723 }
724
725 return bAdded;
726 }
727
728 /************************************************************************/
729 /* AddFeature */
730 /************************************************************************/
731
AddFeature(OGRGeoJSONLayer * poLayer,OGRFeature * poFeature)732 bool OGRGeoJSONReader::AddFeature( OGRGeoJSONLayer* poLayer, OGRFeature* poFeature )
733 {
734 bool bAdded = false;
735
736 if( NULL != poFeature )
737 {
738 poLayer->AddFeature( poFeature );
739 bAdded = true;
740 delete poFeature;
741 }
742
743 return bAdded;
744 }
745
746 /************************************************************************/
747 /* ReadGeometry */
748 /************************************************************************/
749
ReadGeometry(json_object * poObj)750 OGRGeometry* OGRGeoJSONReader::ReadGeometry( json_object* poObj )
751 {
752 OGRGeometry* poGeometry = NULL;
753
754 poGeometry = OGRGeoJSONReadGeometry( poObj );
755
756 /* -------------------------------------------------------------------- */
757 /* Wrap geometry with GeometryCollection as a common denominator. */
758 /* Sometimes a GeoJSON text may consist of objects of different */
759 /* geometry types. Users may request wrapping all geometries with */
760 /* OGRGeometryCollection type by using option */
761 /* GEOMETRY_AS_COLLECTION=NO|YES (NO is default). */
762 /* -------------------------------------------------------------------- */
763 if( NULL != poGeometry )
764 {
765 if( !bGeometryPreserve_
766 && wkbGeometryCollection != poGeometry->getGeometryType() )
767 {
768 OGRGeometryCollection* poMetaGeometry = NULL;
769 poMetaGeometry = new OGRGeometryCollection();
770 poMetaGeometry->addGeometryDirectly( poGeometry );
771 return poMetaGeometry;
772 }
773 }
774
775 return poGeometry;
776 }
777
778 /************************************************************************/
779 /* OGRGeoJSONReaderSetFieldNestedAttribute() */
780 /************************************************************************/
781
OGRGeoJSONReaderSetFieldNestedAttribute(OGRLayer * poLayer,OGRFeature * poFeature,const char * pszAttrPrefix,char chSeparator,json_object * poVal)782 static void OGRGeoJSONReaderSetFieldNestedAttribute(OGRLayer* poLayer,
783 OGRFeature* poFeature,
784 const char* pszAttrPrefix,
785 char chSeparator,
786 json_object* poVal)
787 {
788 json_object_iter it;
789 it.key = NULL;
790 it.val = NULL;
791 it.entry = NULL;
792 json_object_object_foreachC( poVal, it )
793 {
794 char szSeparator[2];
795 szSeparator[0] = chSeparator;
796 szSeparator[1] = 0;
797 CPLString osAttrName(CPLSPrintf("%s%s%s", pszAttrPrefix, szSeparator,
798 it.key));
799 if( it.val != NULL && json_object_get_type(it.val) == json_type_object )
800 {
801 OGRGeoJSONReaderSetFieldNestedAttribute(poLayer, poFeature,
802 osAttrName, chSeparator,
803 it.val);
804 }
805 else
806 {
807 int nField = poFeature->GetFieldIndex(osAttrName);
808 OGRGeoJSONReaderSetField(poLayer, poFeature, nField,
809 osAttrName, it.val, FALSE, 0);
810 }
811 }
812 }
813
814 /************************************************************************/
815 /* OGRGeoJSONReaderSetField() */
816 /************************************************************************/
817
OGRGeoJSONReaderSetField(OGRLayer * poLayer,OGRFeature * poFeature,int nField,const char * pszAttrPrefix,json_object * poVal,bool bFlattenNestedAttributes,char chNestedAttributeSeparator)818 void OGRGeoJSONReaderSetField(OGRLayer* poLayer,
819 OGRFeature* poFeature,
820 int nField,
821 const char* pszAttrPrefix,
822 json_object* poVal,
823 bool bFlattenNestedAttributes,
824 char chNestedAttributeSeparator)
825 {
826 if( bFlattenNestedAttributes &&
827 poVal != NULL && json_object_get_type(poVal) == json_type_object )
828 {
829 OGRGeoJSONReaderSetFieldNestedAttribute(poLayer,
830 poFeature,
831 pszAttrPrefix,
832 chNestedAttributeSeparator,
833 poVal);
834 return ;
835 }
836
837 OGRFieldDefn* poFieldDefn = poFeature->GetFieldDefnRef(nField);
838 CPLAssert( NULL != poFieldDefn );
839 OGRFieldType eType = poFieldDefn->GetType();
840
841 if( poVal == NULL)
842 {
843 /* nothing to do */
844 }
845 else if( OFTInteger == eType )
846 {
847 poFeature->SetField( nField, json_object_get_int(poVal) );
848
849 /* Check if FID available and set correct value. */
850 if( EQUAL( poFieldDefn->GetNameRef(), poLayer->GetFIDColumn() ) )
851 poFeature->SetFID( json_object_get_int(poVal) );
852 }
853 else if( OFTInteger64 == eType )
854 {
855 poFeature->SetField( nField, (GIntBig)json_object_get_int64(poVal) );
856
857 /* Check if FID available and set correct value. */
858 if( EQUAL( poFieldDefn->GetNameRef(), poLayer->GetFIDColumn() ) )
859 poFeature->SetFID( (GIntBig)json_object_get_int64(poVal) );
860 }
861 else if( OFTReal == eType )
862 {
863 poFeature->SetField( nField, json_object_get_double(poVal) );
864 }
865 else if( OFTIntegerList == eType )
866 {
867 if ( json_object_get_type(poVal) == json_type_array )
868 {
869 int nLength = json_object_array_length(poVal);
870 int* panVal = (int*)CPLMalloc(sizeof(int) * nLength);
871 for(int i=0;i<nLength;i++)
872 {
873 json_object* poRow = json_object_array_get_idx(poVal, i);
874 panVal[i] = json_object_get_int(poRow);
875 }
876 poFeature->SetField( nField, nLength, panVal );
877 CPLFree(panVal);
878 }
879 }
880 else if( OFTInteger64List == eType )
881 {
882 if ( json_object_get_type(poVal) == json_type_array )
883 {
884 int nLength = json_object_array_length(poVal);
885 GIntBig* panVal = (GIntBig*)CPLMalloc(sizeof(GIntBig) * nLength);
886 for(int i=0;i<nLength;i++)
887 {
888 json_object* poRow = json_object_array_get_idx(poVal, i);
889 panVal[i] = (GIntBig)json_object_get_int64(poRow);
890 }
891 poFeature->SetField( nField, nLength, panVal );
892 CPLFree(panVal);
893 }
894 }
895 else if( OFTRealList == eType )
896 {
897 if ( json_object_get_type(poVal) == json_type_array )
898 {
899 int nLength = json_object_array_length(poVal);
900 double* padfVal = (double*)CPLMalloc(sizeof(double) * nLength);
901 for(int i=0;i<nLength;i++)
902 {
903 json_object* poRow = json_object_array_get_idx(poVal, i);
904 padfVal[i] = json_object_get_double(poRow);
905 }
906 poFeature->SetField( nField, nLength, padfVal );
907 CPLFree(padfVal);
908 }
909 }
910 else if( OFTStringList == eType )
911 {
912 if ( json_object_get_type(poVal) == json_type_array )
913 {
914 int nLength = json_object_array_length(poVal);
915 char** papszVal = (char**)CPLMalloc(sizeof(char*) * (nLength+1));
916 int i;
917 for(i=0;i<nLength;i++)
918 {
919 json_object* poRow = json_object_array_get_idx(poVal, i);
920 const char* pszVal = json_object_get_string(poRow);
921 if (pszVal == NULL)
922 break;
923 papszVal[i] = CPLStrdup(pszVal);
924 }
925 papszVal[i] = NULL;
926 poFeature->SetField( nField, papszVal );
927 CSLDestroy(papszVal);
928 }
929 }
930 else
931 {
932 poFeature->SetField( nField, json_object_get_string(poVal) );
933 }
934 }
935
936 /************************************************************************/
937 /* ReadFeature() */
938 /************************************************************************/
939
ReadFeature(OGRGeoJSONLayer * poLayer,json_object * poObj)940 OGRFeature* OGRGeoJSONReader::ReadFeature( OGRGeoJSONLayer* poLayer, json_object* poObj )
941 {
942 CPLAssert( NULL != poObj );
943
944 OGRFeature* poFeature = NULL;
945 poFeature = new OGRFeature( poLayer->GetLayerDefn() );
946
947 /* -------------------------------------------------------------------- */
948 /* Translate GeoJSON "properties" object to feature attributes. */
949 /* -------------------------------------------------------------------- */
950 CPLAssert( NULL != poFeature );
951
952 json_object* poObjProps = NULL;
953 poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
954 if( !bAttributesSkip_ && NULL != poObjProps &&
955 json_object_get_type(poObjProps) == json_type_object )
956 {
957 if (bIsGeocouchSpatiallistFormat)
958 {
959 json_object* poId = json_object_object_get(poObjProps, "_id");
960 if (poId != NULL && json_object_get_type(poId) == json_type_string)
961 poFeature->SetField( "_id", json_object_get_string(poId) );
962
963 json_object* poRev = json_object_object_get(poObjProps, "_rev");
964 if (poRev != NULL && json_object_get_type(poRev) == json_type_string)
965 poFeature->SetField( "_rev", json_object_get_string(poRev) );
966
967 poObjProps = json_object_object_get(poObjProps, "properties");
968 if( NULL == poObjProps ||
969 json_object_get_type(poObjProps) != json_type_object )
970 {
971 return poFeature;
972 }
973 }
974
975 int nField = -1;
976 json_object_iter it;
977 it.key = NULL;
978 it.val = NULL;
979 it.entry = NULL;
980 json_object_object_foreachC( poObjProps, it )
981 {
982 nField = poFeature->GetFieldIndex(it.key);
983 OGRGeoJSONReaderSetField(poLayer, poFeature, nField, it.key, it.val,
984 bFlattenNestedAttributes_,
985 chNestedAttributeSeparator_);
986 }
987 }
988
989 if( !bAttributesSkip_ && NULL == poObjProps )
990 {
991 json_object_iter it;
992 it.key = NULL;
993 it.val = NULL;
994 it.entry = NULL;
995 json_object_object_foreachC( poObj, it )
996 {
997 int nFldIndex = poFeature->GetFieldIndex(it.key);
998 if( nFldIndex >= 0 )
999 {
1000 poFeature->SetField(nFldIndex, json_object_get_string(it.val) );
1001 }
1002 }
1003 }
1004
1005 /* -------------------------------------------------------------------- */
1006 /* If FID not set, try to use feature-level ID if available */
1007 /* and of integral type. Otherwise, leave unset (-1) then index */
1008 /* in features sequence will be used as FID. */
1009 /* -------------------------------------------------------------------- */
1010 if( -1 == poFeature->GetFID() )
1011 {
1012 json_object* poObjId = NULL;
1013 OGRFieldSubType eSubType;
1014 poObjId = OGRGeoJSONFindMemberByName( poObj, OGRGeoJSONLayer::DefaultFIDColumn );
1015 if( NULL != poObjId
1016 && EQUAL( OGRGeoJSONLayer::DefaultFIDColumn, poLayer->GetFIDColumn() )
1017 && (OFTInteger == GeoJSONPropertyToFieldType( poObjId, eSubType ) ||
1018 OFTInteger64 == GeoJSONPropertyToFieldType( poObjId, eSubType )) )
1019 {
1020 poFeature->SetFID( (GIntBig)json_object_get_int64( poObjId ) );
1021 int nField = poFeature->GetFieldIndex( poLayer->GetFIDColumn() );
1022 if( -1 != nField )
1023 poFeature->SetField( nField, poFeature->GetFID() );
1024 }
1025 }
1026
1027 if( -1 == poFeature->GetFID() )
1028 {
1029 json_object* poObjId = OGRGeoJSONFindMemberByName( poObj, "id" );
1030 if (poObjId != NULL && json_object_get_type(poObjId) == json_type_int)
1031 poFeature->SetFID( (GIntBig)json_object_get_int64( poObjId ) );
1032 else if (poObjId != NULL && json_object_get_type(poObjId) == json_type_string &&
1033 !poFeature->IsFieldSet(poFeature->GetFieldIndex("id")))
1034 poFeature->SetField( "id", json_object_get_string(poObjId) );
1035 }
1036
1037 /* -------------------------------------------------------------------- */
1038 /* Translate geometry sub-object of GeoJSON Feature. */
1039 /* -------------------------------------------------------------------- */
1040 json_object* poObjGeom = NULL;
1041
1042 json_object* poTmp = poObj;
1043
1044 json_object_iter it;
1045 it.key = NULL;
1046 it.val = NULL;
1047 it.entry = NULL;
1048 json_object_object_foreachC(poTmp, it)
1049 {
1050 if( EQUAL( it.key, "geometry" ) ) {
1051 if (it.val != NULL)
1052 poObjGeom = it.val;
1053 // we're done. They had 'geometry':null
1054 else
1055 return poFeature;
1056 }
1057 }
1058
1059 if( NULL != poObjGeom )
1060 {
1061 // NOTE: If geometry can not be parsed or read correctly
1062 // then NULL geometry is assigned to a feature and
1063 // geometry type for layer is classified as wkbUnknown.
1064 OGRGeometry* poGeometry = ReadGeometry( poObjGeom );
1065 if( NULL != poGeometry )
1066 {
1067 poFeature->SetGeometryDirectly( poGeometry );
1068 }
1069 }
1070 else
1071 {
1072 static int bWarned = FALSE;
1073 if( !bWarned )
1074 {
1075 bWarned = TRUE;
1076 CPLDebug("GeoJSON", "Non conformant Feature object. Missing \'geometry\' member." );
1077 }
1078 }
1079
1080 return poFeature;
1081 }
1082
1083 /************************************************************************/
1084 /* ReadFeatureCollection() */
1085 /************************************************************************/
1086
1087 void
ReadFeatureCollection(OGRGeoJSONLayer * poLayer,json_object * poObj)1088 OGRGeoJSONReader::ReadFeatureCollection( OGRGeoJSONLayer* poLayer, json_object* poObj )
1089 {
1090 json_object* poObjFeatures = NULL;
1091 poObjFeatures = OGRGeoJSONFindMemberByName( poObj, "features" );
1092 if( NULL == poObjFeatures )
1093 {
1094 CPLError( CE_Failure, CPLE_AppDefined,
1095 "Invalid FeatureCollection object. "
1096 "Missing \'features\' member." );
1097 return;
1098 }
1099
1100 if( json_type_array == json_object_get_type( poObjFeatures ) )
1101 {
1102 /* bool bAdded = false; */
1103 OGRFeature* poFeature = NULL;
1104 json_object* poObjFeature = NULL;
1105
1106 const int nFeatures = json_object_array_length( poObjFeatures );
1107 for( int i = 0; i < nFeatures; ++i )
1108 {
1109 poObjFeature = json_object_array_get_idx( poObjFeatures, i );
1110 poFeature = ReadFeature( poLayer, poObjFeature );
1111 /* bAdded = */ AddFeature( poLayer, poFeature );
1112 //CPLAssert( bAdded );
1113 }
1114 //CPLAssert( nFeatures == poLayer_->GetFeatureCount() );
1115 }
1116 }
1117
1118 /************************************************************************/
1119 /* OGRGeoJSONFindMemberByName */
1120 /************************************************************************/
1121
OGRGeoJSONFindMemberByName(json_object * poObj,const char * pszName)1122 json_object* OGRGeoJSONFindMemberByName( json_object* poObj,
1123 const char* pszName )
1124 {
1125 if( NULL == pszName || NULL == poObj)
1126 return NULL;
1127
1128 json_object* poTmp = poObj;
1129
1130 json_object_iter it;
1131 it.key = NULL;
1132 it.val = NULL;
1133 it.entry = NULL;
1134 if( NULL != json_object_get_object(poTmp) &&
1135 NULL != json_object_get_object(poTmp)->head )
1136 {
1137 for( it.entry = json_object_get_object(poTmp)->head;
1138 ( it.entry ?
1139 ( it.key = (char*)it.entry->k,
1140 it.val = (json_object*)it.entry->v, it.entry) : 0);
1141 it.entry = it.entry->next)
1142 {
1143 if( EQUAL( it.key, pszName ) )
1144 return it.val;
1145 }
1146 }
1147
1148 return NULL;
1149 }
1150
1151 /************************************************************************/
1152 /* OGRGeoJSONGetType */
1153 /************************************************************************/
1154
OGRGeoJSONGetType(json_object * poObj)1155 GeoJSONObject::Type OGRGeoJSONGetType( json_object* poObj )
1156 {
1157 if( NULL == poObj )
1158 return GeoJSONObject::eUnknown;
1159
1160 json_object* poObjType = NULL;
1161 poObjType = OGRGeoJSONFindMemberByName( poObj, "type" );
1162 if( NULL == poObjType )
1163 return GeoJSONObject::eUnknown;
1164
1165 const char* name = json_object_get_string( poObjType );
1166 if( EQUAL( name, "Point" ) )
1167 return GeoJSONObject::ePoint;
1168 else if( EQUAL( name, "LineString" ) )
1169 return GeoJSONObject::eLineString;
1170 else if( EQUAL( name, "Polygon" ) )
1171 return GeoJSONObject::ePolygon;
1172 else if( EQUAL( name, "MultiPoint" ) )
1173 return GeoJSONObject::eMultiPoint;
1174 else if( EQUAL( name, "MultiLineString" ) )
1175 return GeoJSONObject::eMultiLineString;
1176 else if( EQUAL( name, "MultiPolygon" ) )
1177 return GeoJSONObject::eMultiPolygon;
1178 else if( EQUAL( name, "GeometryCollection" ) )
1179 return GeoJSONObject::eGeometryCollection;
1180 else if( EQUAL( name, "Feature" ) )
1181 return GeoJSONObject::eFeature;
1182 else if( EQUAL( name, "FeatureCollection" ) )
1183 return GeoJSONObject::eFeatureCollection;
1184 else
1185 return GeoJSONObject::eUnknown;
1186 }
1187
1188 /************************************************************************/
1189 /* OGRGeoJSONReadGeometry */
1190 /************************************************************************/
1191
OGRGeoJSONReadGeometry(json_object * poObj)1192 OGRGeometry* OGRGeoJSONReadGeometry( json_object* poObj )
1193 {
1194 OGRGeometry* poGeometry = NULL;
1195
1196 GeoJSONObject::Type objType = OGRGeoJSONGetType( poObj );
1197 if( GeoJSONObject::ePoint == objType )
1198 poGeometry = OGRGeoJSONReadPoint( poObj );
1199 else if( GeoJSONObject::eMultiPoint == objType )
1200 poGeometry = OGRGeoJSONReadMultiPoint( poObj );
1201 else if( GeoJSONObject::eLineString == objType )
1202 poGeometry = OGRGeoJSONReadLineString( poObj );
1203 else if( GeoJSONObject::eMultiLineString == objType )
1204 poGeometry = OGRGeoJSONReadMultiLineString( poObj );
1205 else if( GeoJSONObject::ePolygon == objType )
1206 poGeometry = OGRGeoJSONReadPolygon( poObj );
1207 else if( GeoJSONObject::eMultiPolygon == objType )
1208 poGeometry = OGRGeoJSONReadMultiPolygon( poObj );
1209 else if( GeoJSONObject::eGeometryCollection == objType )
1210 poGeometry = OGRGeoJSONReadGeometryCollection( poObj );
1211 else
1212 {
1213 CPLDebug( "GeoJSON",
1214 "Unsupported geometry type detected. "
1215 "Feature gets NULL geometry assigned." );
1216 }
1217 // If we have a crs object in the current object, let's try and
1218 // set it too.
1219
1220 json_object* poObjSrs = OGRGeoJSONFindMemberByName( poObj, "crs" );
1221 if (poGeometry != NULL && poObjSrs != NULL) {
1222 OGRSpatialReference* poSRS = OGRGeoJSONReadSpatialReference(poObj);
1223 if (poSRS != NULL) {
1224 poGeometry->assignSpatialReference(poSRS);
1225 poSRS->Release();
1226 }
1227 }
1228 return poGeometry;
1229 }
1230
1231 /************************************************************************/
1232 /* OGRGeoJSONReadRawPoint */
1233 /************************************************************************/
1234
OGRGeoJSONReadRawPoint(json_object * poObj,OGRPoint & point)1235 bool OGRGeoJSONReadRawPoint( json_object* poObj, OGRPoint& point )
1236 {
1237 CPLAssert( NULL != poObj );
1238
1239 if( json_type_array == json_object_get_type( poObj ) )
1240 {
1241 const int nSize = json_object_array_length( poObj );
1242 int iType = 0;
1243
1244 if( nSize != GeoJSONObject::eMinCoordinateDimension
1245 && nSize != GeoJSONObject::eMaxCoordinateDimension )
1246 {
1247 CPLDebug( "GeoJSON",
1248 "Invalid coord dimension. Only 2D and 3D supported." );
1249 return false;
1250 }
1251
1252 json_object* poObjCoord = NULL;
1253
1254 // Read X coordinate
1255 poObjCoord = json_object_array_get_idx( poObj, 0 );
1256 if (poObjCoord == NULL)
1257 {
1258 CPLDebug( "GeoJSON", "Point: got null object." );
1259 return false;
1260 }
1261
1262 iType = json_object_get_type(poObjCoord);
1263 if ( (json_type_double != iType) && (json_type_int != iType) )
1264 {
1265 CPLError( CE_Failure, CPLE_AppDefined,
1266 "Invalid X coordinate. Type is not double or integer for \'%s\'.",
1267 json_object_to_json_string(poObj) );
1268 return false;
1269 }
1270
1271 if (iType == json_type_double)
1272 point.setX(json_object_get_double( poObjCoord ));
1273 else
1274 point.setX(json_object_get_int( poObjCoord ));
1275
1276 // Read Y coordiante
1277 poObjCoord = json_object_array_get_idx( poObj, 1 );
1278 if (poObjCoord == NULL)
1279 {
1280 CPLDebug( "GeoJSON", "Point: got null object." );
1281 return false;
1282 }
1283
1284 iType = json_object_get_type(poObjCoord);
1285 if ( (json_type_double != iType) && (json_type_int != iType) )
1286 {
1287 CPLError( CE_Failure, CPLE_AppDefined,
1288 "Invalid Y coordinate. Type is not double or integer for \'%s\'.",
1289 json_object_to_json_string(poObj) );
1290 return false;
1291 }
1292
1293 if (iType == json_type_double)
1294 point.setY(json_object_get_double( poObjCoord ));
1295 else
1296 point.setY(json_object_get_int( poObjCoord ));
1297
1298 // Read Z coordinate
1299 if( nSize == GeoJSONObject::eMaxCoordinateDimension )
1300 {
1301 // Don't *expect* mixed-dimension geometries, although the
1302 // spec doesn't explicitly forbid this.
1303 poObjCoord = json_object_array_get_idx( poObj, 2 );
1304 if (poObjCoord == NULL)
1305 {
1306 CPLDebug( "GeoJSON", "Point: got null object." );
1307 return false;
1308 }
1309
1310 iType = json_object_get_type(poObjCoord);
1311 if ( (json_type_double != iType) && (json_type_int != iType) )
1312 {
1313 CPLError( CE_Failure, CPLE_AppDefined,
1314 "Invalid Z coordinate. Type is not double or integer for \'%s\'.",
1315 json_object_to_json_string(poObj) );
1316 return false;
1317 }
1318
1319 if (iType == json_type_double)
1320 point.setZ(json_object_get_double( poObjCoord ));
1321 else
1322 point.setZ(json_object_get_int( poObjCoord ));
1323 }
1324 else
1325 {
1326 point.flattenTo2D();
1327 }
1328 return true;
1329 }
1330
1331 return false;
1332 }
1333
1334 /************************************************************************/
1335 /* OGRGeoJSONReadPoint */
1336 /************************************************************************/
1337
OGRGeoJSONReadPoint(json_object * poObj)1338 OGRPoint* OGRGeoJSONReadPoint( json_object* poObj )
1339 {
1340 CPLAssert( NULL != poObj );
1341
1342 json_object* poObjCoords = NULL;
1343 poObjCoords = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1344 if( NULL == poObjCoords )
1345 {
1346 CPLError( CE_Failure, CPLE_AppDefined,
1347 "Invalid Point object. Missing \'coordinates\' member." );
1348 return NULL;
1349 }
1350
1351 OGRPoint* poPoint = new OGRPoint();
1352 if( !OGRGeoJSONReadRawPoint( poObjCoords, *poPoint ) )
1353 {
1354 CPLDebug( "GeoJSON", "Point: raw point parsing failure." );
1355 delete poPoint;
1356 return NULL;
1357 }
1358
1359 return poPoint;
1360 }
1361
1362 /************************************************************************/
1363 /* OGRGeoJSONReadMultiPoint */
1364 /************************************************************************/
1365
OGRGeoJSONReadMultiPoint(json_object * poObj)1366 OGRMultiPoint* OGRGeoJSONReadMultiPoint( json_object* poObj )
1367 {
1368 CPLAssert( NULL != poObj );
1369
1370 OGRMultiPoint* poMultiPoint = NULL;
1371
1372 json_object* poObjPoints = NULL;
1373 poObjPoints = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1374 if( NULL == poObjPoints )
1375 {
1376 CPLError( CE_Failure, CPLE_AppDefined,
1377 "Invalid MultiPoint object. "
1378 "Missing \'coordinates\' member." );
1379 return NULL;
1380 }
1381
1382 if( json_type_array == json_object_get_type( poObjPoints ) )
1383 {
1384 const int nPoints = json_object_array_length( poObjPoints );
1385
1386 poMultiPoint = new OGRMultiPoint();
1387
1388 for( int i = 0; i < nPoints; ++i)
1389 {
1390 json_object* poObjCoords = NULL;
1391 poObjCoords = json_object_array_get_idx( poObjPoints, i );
1392
1393 OGRPoint pt;
1394 if( poObjCoords != NULL && !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
1395 {
1396 delete poMultiPoint;
1397 CPLDebug( "GeoJSON",
1398 "LineString: raw point parsing failure." );
1399 return NULL;
1400 }
1401 poMultiPoint->addGeometry( &pt );
1402 }
1403 }
1404
1405 return poMultiPoint;
1406 }
1407
1408 /************************************************************************/
1409 /* OGRGeoJSONReadLineString */
1410 /************************************************************************/
1411
OGRGeoJSONReadLineString(json_object * poObj,bool bRaw)1412 OGRLineString* OGRGeoJSONReadLineString( json_object* poObj , bool bRaw)
1413 {
1414 CPLAssert( NULL != poObj );
1415
1416 OGRLineString* poLine = NULL;
1417 json_object* poObjPoints = NULL;
1418
1419 if( !bRaw )
1420 {
1421 poObjPoints = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1422 if( NULL == poObjPoints )
1423 {
1424 CPLError( CE_Failure, CPLE_AppDefined,
1425 "Invalid LineString object. "
1426 "Missing \'coordinates\' member." );
1427 return NULL;
1428 }
1429 }
1430 else
1431 {
1432 poObjPoints = poObj;
1433 }
1434
1435 if( json_type_array == json_object_get_type( poObjPoints ) )
1436 {
1437 const int nPoints = json_object_array_length( poObjPoints );
1438
1439 poLine = new OGRLineString();
1440 poLine->setNumPoints( nPoints );
1441
1442 for( int i = 0; i < nPoints; ++i)
1443 {
1444 json_object* poObjCoords = NULL;
1445 poObjCoords = json_object_array_get_idx( poObjPoints, i );
1446 if (poObjCoords == NULL)
1447 {
1448 delete poLine;
1449 CPLDebug( "GeoJSON",
1450 "LineString: got null object." );
1451 return NULL;
1452 }
1453
1454 OGRPoint pt;
1455 if( !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
1456 {
1457 delete poLine;
1458 CPLDebug( "GeoJSON",
1459 "LineString: raw point parsing failure." );
1460 return NULL;
1461 }
1462 if (pt.getCoordinateDimension() == 2) {
1463 poLine->setPoint( i, pt.getX(), pt.getY());
1464 } else {
1465 poLine->setPoint( i, pt.getX(), pt.getY(), pt.getZ() );
1466 }
1467
1468 }
1469 }
1470
1471 return poLine;
1472 }
1473
1474 /************************************************************************/
1475 /* OGRGeoJSONReadMultiLineString */
1476 /************************************************************************/
1477
OGRGeoJSONReadMultiLineString(json_object * poObj)1478 OGRMultiLineString* OGRGeoJSONReadMultiLineString( json_object* poObj )
1479 {
1480 CPLAssert( NULL != poObj );
1481
1482 OGRMultiLineString* poMultiLine = NULL;
1483
1484 json_object* poObjLines = NULL;
1485 poObjLines = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1486 if( NULL == poObjLines )
1487 {
1488 CPLError( CE_Failure, CPLE_AppDefined,
1489 "Invalid MultiLineString object. "
1490 "Missing \'coordinates\' member." );
1491 return NULL;
1492 }
1493
1494 if( json_type_array == json_object_get_type( poObjLines ) )
1495 {
1496 const int nLines = json_object_array_length( poObjLines );
1497
1498 poMultiLine = new OGRMultiLineString();
1499
1500 for( int i = 0; i < nLines; ++i)
1501 {
1502 json_object* poObjLine = NULL;
1503 poObjLine = json_object_array_get_idx( poObjLines, i );
1504
1505 OGRLineString* poLine;
1506 if (poObjLine != NULL)
1507 poLine = OGRGeoJSONReadLineString( poObjLine , true );
1508 else
1509 poLine = new OGRLineString();
1510
1511 if( NULL != poLine )
1512 {
1513 poMultiLine->addGeometryDirectly( poLine );
1514 }
1515 }
1516 }
1517
1518 return poMultiLine;
1519 }
1520
1521 /************************************************************************/
1522 /* OGRGeoJSONReadLinearRing */
1523 /************************************************************************/
1524
OGRGeoJSONReadLinearRing(json_object * poObj)1525 OGRLinearRing* OGRGeoJSONReadLinearRing( json_object* poObj )
1526 {
1527 CPLAssert( NULL != poObj );
1528
1529 OGRLinearRing* poRing = NULL;
1530
1531 if( json_type_array == json_object_get_type( poObj ) )
1532 {
1533 const int nPoints = json_object_array_length( poObj );
1534
1535 poRing= new OGRLinearRing();
1536 poRing->setNumPoints( nPoints );
1537
1538 for( int i = 0; i < nPoints; ++i)
1539 {
1540 json_object* poObjCoords = NULL;
1541 poObjCoords = json_object_array_get_idx( poObj, i );
1542 if (poObjCoords == NULL)
1543 {
1544 delete poRing;
1545 CPLDebug( "GeoJSON",
1546 "LinearRing: got null object." );
1547 return NULL;
1548 }
1549
1550 OGRPoint pt;
1551 if( !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
1552 {
1553 delete poRing;
1554 CPLDebug( "GeoJSON",
1555 "LinearRing: raw point parsing failure." );
1556 return NULL;
1557 }
1558
1559 if( 2 == pt.getCoordinateDimension() )
1560 poRing->setPoint( i, pt.getX(), pt.getY());
1561 else
1562 poRing->setPoint( i, pt.getX(), pt.getY(), pt.getZ() );
1563 }
1564 }
1565
1566 return poRing;
1567 }
1568
1569 /************************************************************************/
1570 /* OGRGeoJSONReadPolygon */
1571 /************************************************************************/
1572
OGRGeoJSONReadPolygon(json_object * poObj,bool bRaw)1573 OGRPolygon* OGRGeoJSONReadPolygon( json_object* poObj , bool bRaw )
1574 {
1575 CPLAssert( NULL != poObj );
1576
1577 OGRPolygon* poPolygon = NULL;
1578
1579 json_object* poObjRings = NULL;
1580
1581 if( !bRaw )
1582 {
1583 poObjRings = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1584 if( NULL == poObjRings )
1585 {
1586 CPLError( CE_Failure, CPLE_AppDefined,
1587 "Invalid Polygon object. "
1588 "Missing \'coordinates\' member." );
1589 return NULL;
1590 }
1591 }
1592 else
1593 {
1594 poObjRings = poObj;
1595 }
1596
1597 if( json_type_array == json_object_get_type( poObjRings ) )
1598 {
1599 const int nRings = json_object_array_length( poObjRings );
1600 if( nRings > 0 )
1601 {
1602 json_object* poObjPoints = NULL;
1603 poObjPoints = json_object_array_get_idx( poObjRings, 0 );
1604 if (poObjPoints == NULL)
1605 {
1606 poPolygon = new OGRPolygon();
1607 poPolygon->addRingDirectly( new OGRLinearRing() );
1608 }
1609 else
1610 {
1611 OGRLinearRing* poRing = OGRGeoJSONReadLinearRing( poObjPoints );
1612 if( NULL != poRing )
1613 {
1614 poPolygon = new OGRPolygon();
1615 poPolygon->addRingDirectly( poRing );
1616 }
1617 }
1618
1619 for( int i = 1; i < nRings && NULL != poPolygon; ++i )
1620 {
1621 poObjPoints = json_object_array_get_idx( poObjRings, i );
1622 if (poObjPoints == NULL)
1623 {
1624 poPolygon->addRingDirectly( new OGRLinearRing() );
1625 }
1626 else
1627 {
1628 OGRLinearRing* poRing = OGRGeoJSONReadLinearRing( poObjPoints );
1629 if( NULL != poRing )
1630 {
1631 poPolygon->addRingDirectly( poRing );
1632 }
1633 }
1634 }
1635 }
1636 }
1637
1638 return poPolygon;
1639 }
1640
1641 /************************************************************************/
1642 /* OGRGeoJSONReadMultiPolygon */
1643 /************************************************************************/
1644
OGRGeoJSONReadMultiPolygon(json_object * poObj)1645 OGRMultiPolygon* OGRGeoJSONReadMultiPolygon( json_object* poObj )
1646 {
1647 CPLAssert( NULL != poObj );
1648
1649 OGRMultiPolygon* poMultiPoly = NULL;
1650
1651 json_object* poObjPolys = NULL;
1652 poObjPolys = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1653 if( NULL == poObjPolys )
1654 {
1655 CPLError( CE_Failure, CPLE_AppDefined,
1656 "Invalid MultiPolygon object. "
1657 "Missing \'coordinates\' member." );
1658 return NULL;
1659 }
1660
1661 if( json_type_array == json_object_get_type( poObjPolys ) )
1662 {
1663 const int nPolys = json_object_array_length( poObjPolys );
1664
1665 poMultiPoly = new OGRMultiPolygon();
1666
1667 for( int i = 0; i < nPolys; ++i)
1668 {
1669
1670 json_object* poObjPoly = NULL;
1671 poObjPoly = json_object_array_get_idx( poObjPolys, i );
1672 if (poObjPoly == NULL)
1673 {
1674 poMultiPoly->addGeometryDirectly( new OGRPolygon() );
1675 }
1676 else
1677 {
1678 OGRPolygon* poPoly = OGRGeoJSONReadPolygon( poObjPoly , true );
1679 if( NULL != poPoly )
1680 {
1681 poMultiPoly->addGeometryDirectly( poPoly );
1682 }
1683 }
1684 }
1685 }
1686
1687 return poMultiPoly;
1688 }
1689 /************************************************************************/
1690 /* OGRGeoJSONReadGeometryCollection */
1691 /************************************************************************/
1692
OGRGeoJSONReadGeometryCollection(json_object * poObj)1693 OGRGeometryCollection* OGRGeoJSONReadGeometryCollection( json_object* poObj )
1694 {
1695 CPLAssert( NULL != poObj );
1696
1697 OGRGeometry* poGeometry = NULL;
1698 OGRGeometryCollection* poCollection = NULL;
1699
1700 json_object* poObjGeoms = NULL;
1701 poObjGeoms = OGRGeoJSONFindMemberByName( poObj, "geometries" );
1702 if( NULL == poObjGeoms )
1703 {
1704 CPLError( CE_Failure, CPLE_AppDefined,
1705 "Invalid GeometryCollection object. "
1706 "Missing \'geometries\' member." );
1707 return NULL;
1708 }
1709
1710 if( json_type_array == json_object_get_type( poObjGeoms ) )
1711 {
1712 const int nGeoms = json_object_array_length( poObjGeoms );
1713 if( nGeoms > 0 )
1714 {
1715 poCollection = new OGRGeometryCollection();
1716 }
1717
1718 json_object* poObjGeom = NULL;
1719 for( int i = 0; i < nGeoms; ++i )
1720 {
1721 poObjGeom = json_object_array_get_idx( poObjGeoms, i );
1722 if (poObjGeom == NULL)
1723 {
1724 CPLDebug( "GeoJSON", "Skipping null sub-geometry");
1725 continue;
1726 }
1727
1728 poGeometry = OGRGeoJSONReadGeometry( poObjGeom );
1729 if( NULL != poGeometry )
1730 {
1731 poCollection->addGeometryDirectly( poGeometry );
1732 }
1733 }
1734 }
1735
1736 return poCollection;
1737 }
1738
1739 /************************************************************************/
1740 /* OGR_G_ExportToJson */
1741 /************************************************************************/
1742
OGR_G_CreateGeometryFromJson(const char * pszJson)1743 OGRGeometryH OGR_G_CreateGeometryFromJson( const char* pszJson )
1744 {
1745 VALIDATE_POINTER1( pszJson, "OGR_G_CreateGeometryFromJson", NULL );
1746
1747 if( NULL != pszJson )
1748 {
1749 json_tokener* jstok = NULL;
1750 json_object* poObj = NULL;
1751
1752 jstok = json_tokener_new();
1753 poObj = json_tokener_parse_ex(jstok, pszJson, -1);
1754 if( jstok->err != json_tokener_success)
1755 {
1756 CPLError( CE_Failure, CPLE_AppDefined,
1757 "GeoJSON parsing error: %s (at offset %d)",
1758 json_tokener_error_desc(jstok->err), jstok->char_offset);
1759 json_tokener_free(jstok);
1760 return NULL;
1761 }
1762 json_tokener_free(jstok);
1763
1764 OGRGeometry* poGeometry = NULL;
1765 poGeometry = OGRGeoJSONReadGeometry( poObj );
1766
1767 /* Assign WGS84 if no CRS defined on geometry */
1768 if( poGeometry && poGeometry->getSpatialReference() == NULL )
1769 {
1770 poGeometry->assignSpatialReference(OGRSpatialReference::GetWGS84SRS());
1771 }
1772
1773 /* Release JSON tree. */
1774 json_object_put( poObj );
1775
1776 return (OGRGeometryH)poGeometry;
1777 }
1778
1779 /* Translation failed */
1780 return NULL;
1781 }
1782