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