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