1 : /******************************************************************************
2 : * $Id: ogrgeojsonreader.cpp 23662 2011-12-30 11:16:59Z 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 66 : OGRGeoJSONReader::OGRGeoJSONReader()
41 : : poGJObject_( NULL ), poLayer_( NULL ),
42 : bGeometryPreserve_( true ),
43 : bAttributesSkip_( false ),
44 66 : bFlattenGeocouchSpatiallistFormat (-1), bFoundId (false), bFoundRev(false), bFoundTypeFeature(false), bIsGeocouchSpatiallistFormat(false)
45 : {
46 : // Take a deep breath and get to work.
47 66 : }
48 :
49 : /************************************************************************/
50 : /* ~OGRGeoJSONReader */
51 : /************************************************************************/
52 :
53 66 : OGRGeoJSONReader::~OGRGeoJSONReader()
54 : {
55 66 : if( NULL != poGJObject_ )
56 : {
57 66 : json_object_put(poGJObject_);
58 : }
59 :
60 66 : poGJObject_ = NULL;
61 66 : poLayer_ = NULL;
62 66 : }
63 :
64 : /************************************************************************/
65 : /* Parse */
66 : /************************************************************************/
67 :
68 66 : OGRErr OGRGeoJSONReader::Parse( const char* pszText )
69 : {
70 66 : if( NULL != pszText )
71 : {
72 66 : json_tokener* jstok = NULL;
73 66 : json_object* jsobj = NULL;
74 :
75 66 : jstok = json_tokener_new();
76 66 : jsobj = json_tokener_parse_ex(jstok, pszText, -1);
77 66 : 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 66 : 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 66 : poGJObject_ = jsobj;
92 : }
93 :
94 66 : return OGRERR_NONE;
95 : }
96 :
97 : /************************************************************************/
98 : /* ReadLayer */
99 : /************************************************************************/
100 :
101 66 : OGRGeoJSONLayer* OGRGeoJSONReader::ReadLayer( const char* pszName,
102 : OGRGeoJSONDataSource* poDS )
103 : {
104 66 : CPLAssert( NULL == poLayer_ );
105 :
106 66 : 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 66 : poDS );
116 :
117 66 : 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 66 : GeoJSONObject::Type objType = OGRGeoJSONGetType( poGJObject_ );
130 :
131 100 : 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 34 : OGRGeometry* poGeometry = NULL;
140 34 : poGeometry = ReadGeometry( poGJObject_ );
141 34 : 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 32 : 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 32 : else if( GeoJSONObject::eFeatureCollection == objType )
169 : {
170 32 : OGRGeoJSONLayer* poThisLayer = NULL;
171 32 : poThisLayer = ReadFeatureCollection( poGJObject_ );
172 32 : 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 66 : OGRSpatialReference* poSRS = NULL;
184 66 : poSRS = OGRGeoJSONReadSpatialReference( poGJObject_ );
185 66 : if (poSRS == NULL ) {
186 : // If there is none defined, we use 4326
187 62 : poSRS = new OGRSpatialReference();
188 62 : if( OGRERR_NONE != poSRS->importFromEPSG( 4326 ) )
189 : {
190 0 : delete poSRS;
191 0 : poSRS = NULL;
192 : }
193 62 : poLayer_->SetSpatialRef( poSRS );
194 62 : delete poSRS;
195 : }
196 : else {
197 4 : poLayer_->SetSpatialRef( poSRS );
198 4 : delete poSRS;
199 : }
200 :
201 : // TODO: FeatureCollection
202 :
203 66 : return poLayer_;
204 : }
205 :
206 74 : OGRSpatialReference* OGRGeoJSONReadSpatialReference( json_object* poObj) {
207 :
208 : /* -------------------------------------------------------------------- */
209 : /* Read spatial reference definition. */
210 : /* -------------------------------------------------------------------- */
211 74 : OGRSpatialReference* poSRS = NULL;
212 :
213 74 : json_object* poObjSrs = OGRGeoJSONFindMemberByName( poObj, "crs" );
214 74 : if( NULL != poObjSrs )
215 : {
216 12 : json_object* poObjSrsType = OGRGeoJSONFindMemberByName( poObjSrs, "type" );
217 12 : if (poObjSrsType == NULL)
218 0 : return NULL;
219 :
220 12 : const char* pszSrsType = json_object_get_string( poObjSrsType );
221 :
222 : // TODO: Add URL and URN types support
223 12 : if( EQUALN( pszSrsType, "NAME", 4 ) )
224 : {
225 12 : json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
226 12 : if (poObjSrsProps == NULL)
227 0 : return NULL;
228 :
229 12 : json_object* poNameURL = OGRGeoJSONFindMemberByName( poObjSrsProps, "name" );
230 12 : if (poNameURL == NULL)
231 0 : return NULL;
232 :
233 12 : const char* pszName = json_object_get_string( poNameURL );
234 :
235 12 : poSRS = new OGRSpatialReference();
236 12 : if( OGRERR_NONE != poSRS->SetFromUserInput( pszName ) )
237 : {
238 0 : delete poSRS;
239 0 : poSRS = NULL;
240 : }
241 : }
242 :
243 12 : if( EQUALN( pszSrsType, "EPSG", 4 ) )
244 : {
245 0 : json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
246 0 : if (poObjSrsProps == NULL)
247 0 : return NULL;
248 :
249 0 : json_object* poObjCode = OGRGeoJSONFindMemberByName( poObjSrsProps, "code" );
250 0 : if (poObjCode == NULL)
251 0 : return NULL;
252 :
253 0 : int nEPSG = json_object_get_int( poObjCode );
254 :
255 0 : poSRS = new OGRSpatialReference();
256 0 : if( OGRERR_NONE != poSRS->importFromEPSG( nEPSG ) )
257 : {
258 0 : delete poSRS;
259 0 : poSRS = NULL;
260 : }
261 : }
262 :
263 12 : 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 12 : 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 74 : 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 66 : bool OGRGeoJSONReader::GenerateLayerDefn()
333 : {
334 66 : CPLAssert( NULL != poGJObject_ );
335 66 : CPLAssert( NULL != poLayer_->GetLayerDefn() );
336 66 : CPLAssert( 0 == poLayer_->GetLayerDefn()->GetFieldCount() );
337 :
338 66 : bool bSuccess = true;
339 :
340 66 : if( bAttributesSkip_ )
341 0 : return true;
342 :
343 : /* -------------------------------------------------------------------- */
344 : /* Scan all features and generate layer definition. */
345 : /* -------------------------------------------------------------------- */
346 66 : GeoJSONObject::Type objType = OGRGeoJSONGetType( poGJObject_ );
347 66 : if( GeoJSONObject::eFeature == objType )
348 : {
349 0 : bSuccess = GenerateFeatureDefn( poGJObject_ );
350 : }
351 66 : else if( GeoJSONObject::eFeatureCollection == objType )
352 : {
353 32 : json_object* poObjFeatures = NULL;
354 32 : poObjFeatures = OGRGeoJSONFindMemberByName( poGJObject_, "features" );
355 32 : if( NULL != poObjFeatures
356 : && json_type_array == json_object_get_type( poObjFeatures ) )
357 : {
358 32 : json_object* poObjFeature = NULL;
359 32 : const int nFeatures = json_object_array_length( poObjFeatures );
360 170 : for( int i = 0; i < nFeatures; ++i )
361 : {
362 138 : poObjFeature = json_object_array_get_idx( poObjFeatures, i );
363 138 : 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 66 : OGRFeatureDefn* poLayerDefn = poLayer_->GetLayerDefn();
383 66 : CPLAssert( NULL != poLayerDefn );
384 :
385 66 : bool bHasFID = false;
386 :
387 136 : for( int i = 0; i < poLayerDefn->GetFieldCount(); ++i )
388 : {
389 70 : OGRFieldDefn* poDefn = poLayerDefn->GetFieldDefn(i);
390 70 : 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 66 : return bSuccess;
412 : }
413 :
414 142 : bool OGRGeoJSONReader::GenerateFeatureDefn( json_object* poObj )
415 : {
416 142 : OGRFeatureDefn* poDefn = poLayer_->GetLayerDefn();
417 142 : CPLAssert( NULL != poDefn );
418 :
419 142 : bool bSuccess = false;
420 :
421 : /* -------------------------------------------------------------------- */
422 : /* Read collection of properties. */
423 : /* -------------------------------------------------------------------- */
424 142 : json_object* poObjProps = NULL;
425 142 : poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
426 142 : if( NULL != poObjProps &&
427 : json_object_get_type(poObjProps) == json_type_object )
428 : {
429 142 : if (bIsGeocouchSpatiallistFormat)
430 : {
431 6 : poObjProps = json_object_object_get(poObjProps, "properties");
432 6 : 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 142 : it.key = NULL;
441 142 : it.val = NULL;
442 142 : it.entry = NULL;
443 218 : json_object_object_foreachC( poObjProps, it )
444 : {
445 80 : int nFldIndex = poDefn->GetFieldIndex( it.key );
446 80 : 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 78 : if (strcmp(it.key, "_id") == 0)
451 4 : bFoundId = true;
452 78 : else if (bFoundId && strcmp(it.key, "_rev") == 0)
453 4 : bFoundRev = true;
454 70 : 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 4 : bFoundTypeFeature = true;
458 66 : else if (bFoundTypeFeature && strcmp(it.key, "properties") == 0 &&
459 : it.val != NULL && json_object_get_type(it.val) == json_type_object)
460 : {
461 4 : if (bFlattenGeocouchSpatiallistFormat < 0)
462 : bFlattenGeocouchSpatiallistFormat = CSLTestBoolean(
463 4 : CPLGetConfigOption("GEOJSON_FLATTEN_GEOCOUCH", "TRUE"));
464 4 : if (bFlattenGeocouchSpatiallistFormat)
465 : {
466 4 : poDefn->DeleteFieldDefn(poDefn->GetFieldIndex("type"));
467 4 : bIsGeocouchSpatiallistFormat = true;
468 4 : return GenerateFeatureDefn(poObj);
469 : }
470 : }
471 :
472 : OGRFieldDefn fldDefn( it.key,
473 74 : GeoJSONPropertyToFieldType( it.val ) );
474 74 : poDefn->AddFieldDefn( &fldDefn );
475 : }
476 : else
477 : {
478 2 : OGRFieldDefn* poFDefn = poDefn->GetFieldDefn(nFldIndex);
479 2 : OGRFieldType eType = poFDefn->GetType();
480 2 : if( eType == OFTInteger )
481 : {
482 2 : OGRFieldType eNewType = GeoJSONPropertyToFieldType( it.val );
483 2 : if( eNewType == OFTReal )
484 2 : poFDefn->SetType(eNewType);
485 : }
486 : }
487 : }
488 :
489 138 : 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 138 : return bSuccess;
499 : }
500 :
501 : /************************************************************************/
502 : /* AddFeature */
503 : /************************************************************************/
504 :
505 34 : bool OGRGeoJSONReader::AddFeature( OGRGeometry* poGeometry )
506 : {
507 34 : bool bAdded = false;
508 :
509 : // TODO: Should we check if geometry is of type of
510 : // wkbGeometryCollection ?
511 :
512 34 : if( NULL != poGeometry )
513 : {
514 34 : OGRFeature* poFeature = NULL;
515 34 : poFeature = new OGRFeature( poLayer_->GetLayerDefn() );
516 34 : poFeature->SetGeometryDirectly( poGeometry );
517 :
518 34 : bAdded = AddFeature( poFeature );
519 : }
520 :
521 34 : return bAdded;
522 : }
523 :
524 : /************************************************************************/
525 : /* AddFeature */
526 : /************************************************************************/
527 :
528 172 : bool OGRGeoJSONReader::AddFeature( OGRFeature* poFeature )
529 : {
530 172 : bool bAdded = false;
531 :
532 172 : if( NULL != poFeature )
533 : {
534 168 : poLayer_->AddFeature( poFeature );
535 168 : bAdded = true;
536 168 : delete poFeature;
537 : }
538 :
539 172 : return bAdded;
540 : }
541 :
542 : /************************************************************************/
543 : /* ReadGeometry */
544 : /************************************************************************/
545 :
546 168 : OGRGeometry* OGRGeoJSONReader::ReadGeometry( json_object* poObj )
547 : {
548 168 : OGRGeometry* poGeometry = NULL;
549 :
550 168 : 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 168 : if( NULL != poGeometry )
560 : {
561 112 : 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 168 : return poGeometry;
572 : }
573 :
574 : /************************************************************************/
575 : /* ReadFeature() */
576 : /************************************************************************/
577 :
578 138 : OGRFeature* OGRGeoJSONReader::ReadFeature( json_object* poObj )
579 : {
580 138 : CPLAssert( NULL != poObj );
581 138 : CPLAssert( NULL != poLayer_ );
582 :
583 138 : OGRFeature* poFeature = NULL;
584 138 : poFeature = new OGRFeature( poLayer_->GetLayerDefn() );
585 :
586 : /* -------------------------------------------------------------------- */
587 : /* Translate GeoJSON "properties" object to feature attributes. */
588 : /* -------------------------------------------------------------------- */
589 138 : CPLAssert( NULL != poFeature );
590 :
591 138 : json_object* poObjProps = NULL;
592 138 : poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
593 138 : if( !bAttributesSkip_ && NULL != poObjProps &&
594 : json_object_get_type(poObjProps) == json_type_object )
595 : {
596 138 : if (bIsGeocouchSpatiallistFormat)
597 : {
598 6 : json_object* poId = json_object_object_get(poObjProps, "_id");
599 6 : if (poId != NULL && json_object_get_type(poId) == json_type_string)
600 6 : poFeature->SetField( "_id", json_object_get_string(poId) );
601 :
602 6 : json_object* poRev = json_object_object_get(poObjProps, "_rev");
603 6 : if (poRev != NULL && json_object_get_type(poRev) == json_type_string)
604 6 : poFeature->SetField( "_rev", json_object_get_string(poRev) );
605 :
606 6 : poObjProps = json_object_object_get(poObjProps, "properties");
607 6 : if( NULL == poObjProps ||
608 : json_object_get_type(poObjProps) != json_type_object )
609 : {
610 0 : return poFeature;
611 : }
612 : }
613 :
614 138 : int nField = -1;
615 138 : OGRFieldDefn* poFieldDefn = NULL;
616 : json_object_iter it;
617 138 : it.key = NULL;
618 138 : it.val = NULL;
619 138 : it.entry = NULL;
620 202 : json_object_object_foreachC( poObjProps, it )
621 : {
622 64 : nField = poFeature->GetFieldIndex(it.key);
623 64 : poFieldDefn = poFeature->GetFieldDefnRef(nField);
624 64 : CPLAssert( NULL != poFieldDefn );
625 64 : OGRFieldType eType = poFieldDefn->GetType();
626 :
627 64 : if( it.val == NULL)
628 : {
629 : /* nothing to do */
630 : }
631 64 : else if( OFTInteger == eType )
632 : {
633 2 : poFeature->SetField( nField, json_object_get_int(it.val) );
634 :
635 : /* Check if FID available and set correct value. */
636 2 : if( EQUAL( it.key, poLayer_->GetFIDColumn() ) )
637 0 : poFeature->SetFID( json_object_get_int(it.val) );
638 : }
639 62 : else if( OFTReal == eType )
640 : {
641 32 : poFeature->SetField( nField, json_object_get_double(it.val) );
642 : }
643 30 : 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 30 : else if( OFTRealList == eType )
659 : {
660 0 : if ( json_object_get_type(it.val) == json_type_array )
661 : {
662 0 : int nLength = json_object_array_length(it.val);
663 0 : double* padfVal = (double*)CPLMalloc(sizeof(double) * nLength);
664 0 : for(int i=0;i<nLength;i++)
665 : {
666 0 : json_object* poRow = json_object_array_get_idx(it.val, i);
667 0 : padfVal[i] = json_object_get_double(poRow);
668 : }
669 0 : poFeature->SetField( nField, nLength, padfVal );
670 0 : CPLFree(padfVal);
671 : }
672 : }
673 30 : 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 30 : 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 138 : if( -1 == poFeature->GetFID() )
706 : {
707 138 : json_object* poObjId = NULL;
708 138 : poObjId = OGRGeoJSONFindMemberByName( poObj, OGRGeoJSONLayer::DefaultFIDColumn );
709 138 : if( NULL != poObjId
710 0 : && 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 138 : if( -1 == poFeature->GetFID() )
721 : {
722 138 : json_object* poObjId = OGRGeoJSONFindMemberByName( poObj, "id" );
723 138 : 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 138 : json_object* poObjGeom = NULL;
731 :
732 138 : json_object* poTmp = poObj;
733 :
734 : json_object_iter it;
735 138 : it.key = NULL;
736 138 : it.val = NULL;
737 138 : it.entry = NULL;
738 548 : json_object_object_foreachC(poTmp, it)
739 : {
740 410 : if( EQUAL( it.key, "geometry" ) ) {
741 134 : if (it.val != NULL)
742 134 : poObjGeom = it.val;
743 : // we're done. They had 'geometry':null
744 : else
745 0 : return poFeature;
746 : }
747 : }
748 :
749 138 : 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 134 : OGRGeometry* poGeometry = ReadGeometry( poObjGeom );
755 134 : if( NULL != poGeometry )
756 : {
757 78 : poFeature->SetGeometryDirectly( poGeometry );
758 : }
759 : }
760 : else
761 : {
762 : CPLError( CE_Failure, CPLE_AppDefined,
763 : "Invalid Feature object. "
764 4 : "Missing \'geometry\' member." );
765 4 : delete poFeature;
766 4 : return NULL;
767 : }
768 :
769 134 : return poFeature;
770 : }
771 :
772 : /************************************************************************/
773 : /* ReadFeatureCollection() */
774 : /************************************************************************/
775 :
776 : OGRGeoJSONLayer*
777 32 : OGRGeoJSONReader::ReadFeatureCollection( json_object* poObj )
778 : {
779 32 : CPLAssert( NULL != poLayer_ );
780 :
781 32 : json_object* poObjFeatures = NULL;
782 32 : poObjFeatures = OGRGeoJSONFindMemberByName( poObj, "features" );
783 32 : 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 32 : if( json_type_array == json_object_get_type( poObjFeatures ) )
792 : {
793 32 : bool bAdded = false;
794 32 : OGRFeature* poFeature = NULL;
795 32 : json_object* poObjFeature = NULL;
796 :
797 32 : const int nFeatures = json_object_array_length( poObjFeatures );
798 170 : for( int i = 0; i < nFeatures; ++i )
799 : {
800 138 : poObjFeature = json_object_array_get_idx( poObjFeatures, i );
801 138 : poFeature = OGRGeoJSONReader::ReadFeature( poObjFeature );
802 138 : 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 32 : CPLAssert( NULL != poLayer_ );
811 32 : return poLayer_;
812 : }
813 :
814 : /************************************************************************/
815 : /* OGRGeoJSONFindMemberByName */
816 : /************************************************************************/
817 :
818 2056 : json_object* OGRGeoJSONFindMemberByName( json_object* poObj,
819 : const char* pszName )
820 : {
821 2056 : if( NULL == pszName || NULL == poObj)
822 0 : return NULL;
823 :
824 2056 : json_object* poTmp = poObj;
825 :
826 : json_object_iter it;
827 2056 : it.key = NULL;
828 2056 : it.val = NULL;
829 2056 : it.entry = NULL;
830 2056 : if( NULL != json_object_get_object(poTmp) &&
831 : NULL != json_object_get_object(poTmp)->head )
832 : {
833 4932 : for( it.entry = json_object_get_object(poTmp)->head;
834 : ( it.entry ?
835 : ( it.key = (char*)it.entry->k,
836 : it.val = (json_object*)it.entry->v, it.entry) : 0);
837 : it.entry = it.entry->next)
838 : {
839 4248 : if( EQUAL( it.key, pszName ) )
840 1372 : return it.val;
841 : }
842 : }
843 :
844 684 : return NULL;
845 : }
846 :
847 : /************************************************************************/
848 : /* OGRGeoJSONGetType */
849 : /************************************************************************/
850 :
851 462 : GeoJSONObject::Type OGRGeoJSONGetType( json_object* poObj )
852 : {
853 462 : if( NULL == poObj )
854 0 : return GeoJSONObject::eUnknown;
855 :
856 462 : json_object* poObjType = NULL;
857 462 : poObjType = OGRGeoJSONFindMemberByName( poObj, "type" );
858 462 : if( NULL == poObjType )
859 0 : return GeoJSONObject::eUnknown;
860 :
861 462 : const char* name = json_object_get_string( poObjType );
862 462 : if( EQUAL( name, "Point" ) )
863 60 : return GeoJSONObject::ePoint;
864 402 : else if( EQUAL( name, "LineString" ) )
865 40 : return GeoJSONObject::eLineString;
866 362 : else if( EQUAL( name, "Polygon" ) )
867 174 : return GeoJSONObject::ePolygon;
868 188 : else if( EQUAL( name, "MultiPoint" ) )
869 28 : return GeoJSONObject::eMultiPoint;
870 160 : else if( EQUAL( name, "MultiLineString" ) )
871 28 : return GeoJSONObject::eMultiLineString;
872 132 : else if( EQUAL( name, "MultiPolygon" ) )
873 32 : return GeoJSONObject::eMultiPolygon;
874 100 : else if( EQUAL( name, "GeometryCollection" ) )
875 36 : return GeoJSONObject::eGeometryCollection;
876 64 : else if( EQUAL( name, "Feature" ) )
877 0 : return GeoJSONObject::eFeature;
878 64 : else if( EQUAL( name, "FeatureCollection" ) )
879 64 : return GeoJSONObject::eFeatureCollection;
880 : else
881 0 : return GeoJSONObject::eUnknown;
882 : }
883 :
884 : /************************************************************************/
885 : /* OGRGeoJSONReadGeometry */
886 : /************************************************************************/
887 :
888 330 : OGRGeometry* OGRGeoJSONReadGeometry( json_object* poObj )
889 : {
890 330 : OGRGeometry* poGeometry = NULL;
891 :
892 330 : GeoJSONObject::Type objType = OGRGeoJSONGetType( poObj );
893 330 : if( GeoJSONObject::ePoint == objType )
894 48 : poGeometry = OGRGeoJSONReadPoint( poObj );
895 282 : else if( GeoJSONObject::eMultiPoint == objType )
896 20 : poGeometry = OGRGeoJSONReadMultiPoint( poObj );
897 262 : else if( GeoJSONObject::eLineString == objType )
898 32 : poGeometry = OGRGeoJSONReadLineString( poObj );
899 230 : else if( GeoJSONObject::eMultiLineString == objType )
900 20 : poGeometry = OGRGeoJSONReadMultiLineString( poObj );
901 210 : else if( GeoJSONObject::ePolygon == objType )
902 166 : poGeometry = OGRGeoJSONReadPolygon( poObj );
903 44 : else if( GeoJSONObject::eMultiPolygon == objType )
904 24 : poGeometry = OGRGeoJSONReadMultiPolygon( poObj );
905 20 : else if( GeoJSONObject::eGeometryCollection == objType )
906 20 : poGeometry = OGRGeoJSONReadGeometryCollection( poObj );
907 : else
908 : {
909 : CPLDebug( "GeoJSON",
910 : "Unsupported geometry type detected. "
911 0 : "Feature gets NULL geometry assigned." );
912 : }
913 : // If we have a crs object in the current object, let's try and
914 : // set it too.
915 :
916 330 : json_object* poObjSrs = OGRGeoJSONFindMemberByName( poObj, "crs" );
917 330 : if (poObjSrs != NULL) {
918 8 : OGRSpatialReference* poSRS = OGRGeoJSONReadSpatialReference(poObj);
919 8 : if (poSRS != NULL) {
920 8 : poGeometry->assignSpatialReference(poSRS);
921 8 : poSRS->Release();
922 : }
923 : }
924 330 : return poGeometry;
925 : }
926 :
927 : /************************************************************************/
928 : /* OGRGeoJSONReadRawPoint */
929 : /************************************************************************/
930 :
931 3978 : bool OGRGeoJSONReadRawPoint( json_object* poObj, OGRPoint& point )
932 : {
933 3978 : CPLAssert( NULL != poObj );
934 :
935 3978 : if( json_type_array == json_object_get_type( poObj ) )
936 : {
937 3978 : const int nSize = json_object_array_length( poObj );
938 3978 : int iType = 0;
939 :
940 3978 : if( nSize != GeoJSONObject::eMinCoordinateDimension
941 : && nSize != GeoJSONObject::eMaxCoordinateDimension )
942 : {
943 : CPLDebug( "GeoJSON",
944 4 : "Invalid coord dimension. Only 2D and 3D supported." );
945 4 : return false;
946 : }
947 :
948 3974 : json_object* poObjCoord = NULL;
949 :
950 : // Read X coordinate
951 3974 : poObjCoord = json_object_array_get_idx( poObj, 0 );
952 3974 : if (poObjCoord == NULL)
953 : {
954 8 : CPLDebug( "GeoJSON", "Point: got null object." );
955 8 : return false;
956 : }
957 :
958 3966 : iType = json_object_get_type(poObjCoord);
959 3966 : if ( (json_type_double != iType) && (json_type_int != iType) )
960 : {
961 : CPLError( CE_Failure, CPLE_AppDefined,
962 : "Invalid X coordinate. Type is not double or integer for \'%s\'.",
963 0 : json_object_to_json_string(poObj) );
964 0 : return false;
965 : }
966 :
967 3966 : if (iType == json_type_double)
968 3896 : point.setX(json_object_get_double( poObjCoord ));
969 : else
970 70 : point.setX(json_object_get_int( poObjCoord ));
971 :
972 : // Read Y coordiante
973 3966 : poObjCoord = json_object_array_get_idx( poObj, 1 );
974 3966 : if (poObjCoord == NULL)
975 : {
976 4 : CPLDebug( "GeoJSON", "Point: got null object." );
977 4 : return false;
978 : }
979 :
980 3962 : iType = json_object_get_type(poObjCoord);
981 3962 : if ( (json_type_double != iType) && (json_type_int != iType) )
982 : {
983 : CPLError( CE_Failure, CPLE_AppDefined,
984 : "Invalid Y coordinate. Type is not double or integer for \'%s\'.",
985 0 : json_object_to_json_string(poObj) );
986 0 : return false;
987 : }
988 :
989 3962 : if (iType == json_type_double)
990 3896 : point.setY(json_object_get_double( poObjCoord ));
991 : else
992 66 : point.setY(json_object_get_int( poObjCoord ));
993 :
994 : // Read Z coordinate
995 3962 : if( nSize == GeoJSONObject::eMaxCoordinateDimension )
996 : {
997 : // Don't *expect* mixed-dimension geometries, although the
998 : // spec doesn't explicitly forbid this.
999 4 : poObjCoord = json_object_array_get_idx( poObj, 2 );
1000 4 : if (poObjCoord == NULL)
1001 : {
1002 4 : CPLDebug( "GeoJSON", "Point: got null object." );
1003 4 : return false;
1004 : }
1005 :
1006 0 : iType = json_object_get_type(poObjCoord);
1007 0 : if ( (json_type_double != iType) && (json_type_int != iType) )
1008 : {
1009 : CPLError( CE_Failure, CPLE_AppDefined,
1010 : "Invalid Z coordinate. Type is not double or integer for \'%s\'.",
1011 0 : json_object_to_json_string(poObj) );
1012 0 : return false;
1013 : }
1014 :
1015 0 : if (iType == json_type_double)
1016 0 : point.setZ(json_object_get_double( poObjCoord ));
1017 : else
1018 0 : point.setZ(json_object_get_int( poObjCoord ));
1019 : }
1020 : else
1021 : {
1022 3958 : point.flattenTo2D();
1023 : }
1024 3958 : return true;
1025 : }
1026 :
1027 0 : return false;
1028 : }
1029 :
1030 : /************************************************************************/
1031 : /* OGRGeoJSONReadPoint */
1032 : /************************************************************************/
1033 :
1034 48 : OGRPoint* OGRGeoJSONReadPoint( json_object* poObj )
1035 : {
1036 48 : CPLAssert( NULL != poObj );
1037 :
1038 48 : json_object* poObjCoords = NULL;
1039 48 : poObjCoords = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1040 48 : if( NULL == poObjCoords )
1041 : {
1042 : CPLError( CE_Failure, CPLE_AppDefined,
1043 4 : "Invalid Point object. Missing \'coordinates\' member." );
1044 4 : return NULL;
1045 : }
1046 :
1047 44 : OGRPoint* poPoint = new OGRPoint();
1048 44 : if( !OGRGeoJSONReadRawPoint( poObjCoords, *poPoint ) )
1049 : {
1050 20 : CPLDebug( "GeoJSON", "Point: raw point parsing failure." );
1051 20 : delete poPoint;
1052 20 : return NULL;
1053 : }
1054 :
1055 24 : return poPoint;
1056 : }
1057 :
1058 : /************************************************************************/
1059 : /* OGRGeoJSONReadMultiPoint */
1060 : /************************************************************************/
1061 :
1062 20 : OGRMultiPoint* OGRGeoJSONReadMultiPoint( json_object* poObj )
1063 : {
1064 20 : CPLAssert( NULL != poObj );
1065 :
1066 20 : OGRMultiPoint* poMultiPoint = NULL;
1067 :
1068 20 : json_object* poObjPoints = NULL;
1069 20 : poObjPoints = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1070 20 : if( NULL == poObjPoints )
1071 : {
1072 : CPLError( CE_Failure, CPLE_AppDefined,
1073 : "Invalid MultiPoint object. "
1074 4 : "Missing \'coordinates\' member." );
1075 4 : return NULL;
1076 : }
1077 :
1078 16 : if( json_type_array == json_object_get_type( poObjPoints ) )
1079 : {
1080 16 : const int nPoints = json_object_array_length( poObjPoints );
1081 :
1082 16 : poMultiPoint = new OGRMultiPoint();
1083 :
1084 16 : for( int i = 0; i < nPoints; ++i)
1085 : {
1086 36 : json_object* poObjCoords = NULL;
1087 36 : poObjCoords = json_object_array_get_idx( poObjPoints, i );
1088 :
1089 36 : OGRPoint pt;
1090 36 : if( poObjCoords != NULL && !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
1091 : {
1092 0 : delete poMultiPoint;
1093 : CPLDebug( "GeoJSON",
1094 0 : "LineString: raw point parsing failure." );
1095 0 : return NULL;
1096 : }
1097 36 : poMultiPoint->addGeometry( &pt );
1098 : }
1099 : }
1100 :
1101 16 : return poMultiPoint;
1102 : }
1103 :
1104 : /************************************************************************/
1105 : /* OGRGeoJSONReadLineString */
1106 : /************************************************************************/
1107 :
1108 60 : OGRLineString* OGRGeoJSONReadLineString( json_object* poObj , bool bRaw)
1109 : {
1110 60 : CPLAssert( NULL != poObj );
1111 :
1112 60 : OGRLineString* poLine = NULL;
1113 60 : json_object* poObjPoints = NULL;
1114 :
1115 60 : if( !bRaw )
1116 : {
1117 32 : poObjPoints = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1118 32 : if( NULL == poObjPoints )
1119 : {
1120 : CPLError( CE_Failure, CPLE_AppDefined,
1121 : "Invalid LineString object. "
1122 4 : "Missing \'coordinates\' member." );
1123 4 : return NULL;
1124 : }
1125 : }
1126 : else
1127 : {
1128 28 : poObjPoints = poObj;
1129 : }
1130 :
1131 56 : if( json_type_array == json_object_get_type( poObjPoints ) )
1132 : {
1133 56 : const int nPoints = json_object_array_length( poObjPoints );
1134 :
1135 56 : poLine = new OGRLineString();
1136 56 : poLine->setNumPoints( nPoints );
1137 :
1138 56 : for( int i = 0; i < nPoints; ++i)
1139 : {
1140 104 : json_object* poObjCoords = NULL;
1141 104 : poObjCoords = json_object_array_get_idx( poObjPoints, i );
1142 104 : if (poObjCoords == NULL)
1143 : {
1144 16 : delete poLine;
1145 : CPLDebug( "GeoJSON",
1146 16 : "LineString: got null object." );
1147 16 : return NULL;
1148 : }
1149 :
1150 88 : OGRPoint pt;
1151 88 : if( !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
1152 : {
1153 0 : delete poLine;
1154 : CPLDebug( "GeoJSON",
1155 0 : "LineString: raw point parsing failure." );
1156 0 : return NULL;
1157 : }
1158 88 : if (pt.getCoordinateDimension() == 2) {
1159 88 : poLine->setPoint( i, pt.getX(), pt.getY());
1160 : } else {
1161 0 : poLine->setPoint( i, pt.getX(), pt.getY(), pt.getZ() );
1162 : }
1163 :
1164 : }
1165 : }
1166 :
1167 40 : return poLine;
1168 : }
1169 :
1170 : /************************************************************************/
1171 : /* OGRGeoJSONReadMultiLineString */
1172 : /************************************************************************/
1173 :
1174 20 : OGRMultiLineString* OGRGeoJSONReadMultiLineString( json_object* poObj )
1175 : {
1176 20 : CPLAssert( NULL != poObj );
1177 :
1178 20 : OGRMultiLineString* poMultiLine = NULL;
1179 :
1180 20 : json_object* poObjLines = NULL;
1181 20 : poObjLines = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1182 20 : if( NULL == poObjLines )
1183 : {
1184 : CPLError( CE_Failure, CPLE_AppDefined,
1185 : "Invalid MultiLineString object. "
1186 4 : "Missing \'coordinates\' member." );
1187 4 : return NULL;
1188 : }
1189 :
1190 16 : if( json_type_array == json_object_get_type( poObjLines ) )
1191 : {
1192 16 : const int nLines = json_object_array_length( poObjLines );
1193 :
1194 16 : poMultiLine = new OGRMultiLineString();
1195 :
1196 52 : for( int i = 0; i < nLines; ++i)
1197 : {
1198 36 : json_object* poObjLine = NULL;
1199 36 : poObjLine = json_object_array_get_idx( poObjLines, i );
1200 :
1201 : OGRLineString* poLine;
1202 36 : if (poObjLine != NULL)
1203 28 : poLine = OGRGeoJSONReadLineString( poObjLine , true );
1204 : else
1205 8 : poLine = new OGRLineString();
1206 :
1207 36 : if( NULL != poLine )
1208 : {
1209 28 : poMultiLine->addGeometryDirectly( poLine );
1210 : }
1211 : }
1212 : }
1213 :
1214 16 : return poMultiLine;
1215 : }
1216 :
1217 : /************************************************************************/
1218 : /* OGRGeoJSONReadLinearRing */
1219 : /************************************************************************/
1220 :
1221 186 : OGRLinearRing* OGRGeoJSONReadLinearRing( json_object* poObj )
1222 : {
1223 186 : CPLAssert( NULL != poObj );
1224 :
1225 186 : OGRLinearRing* poRing = NULL;
1226 :
1227 186 : if( json_type_array == json_object_get_type( poObj ) )
1228 : {
1229 186 : const int nPoints = json_object_array_length( poObj );
1230 :
1231 186 : poRing= new OGRLinearRing();
1232 186 : poRing->setNumPoints( nPoints );
1233 :
1234 186 : for( int i = 0; i < nPoints; ++i)
1235 : {
1236 3822 : json_object* poObjCoords = NULL;
1237 3822 : poObjCoords = json_object_array_get_idx( poObj, i );
1238 3822 : if (poObjCoords == NULL)
1239 : {
1240 0 : delete poRing;
1241 : CPLDebug( "GeoJSON",
1242 0 : "LinearRing: got null object." );
1243 0 : return NULL;
1244 : }
1245 :
1246 3822 : OGRPoint pt;
1247 3822 : if( !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
1248 : {
1249 0 : delete poRing;
1250 : CPLDebug( "GeoJSON",
1251 0 : "LinearRing: raw point parsing failure." );
1252 0 : return NULL;
1253 : }
1254 :
1255 3822 : if( 2 == pt.getCoordinateDimension() )
1256 3822 : poRing->setPoint( i, pt.getX(), pt.getY());
1257 : else
1258 0 : poRing->setPoint( i, pt.getX(), pt.getY(), pt.getZ() );
1259 : }
1260 : }
1261 :
1262 186 : return poRing;
1263 : }
1264 :
1265 : /************************************************************************/
1266 : /* OGRGeoJSONReadPolygon */
1267 : /************************************************************************/
1268 :
1269 198 : OGRPolygon* OGRGeoJSONReadPolygon( json_object* poObj , bool bRaw )
1270 : {
1271 198 : CPLAssert( NULL != poObj );
1272 :
1273 198 : OGRPolygon* poPolygon = NULL;
1274 :
1275 198 : json_object* poObjRings = NULL;
1276 :
1277 198 : if( !bRaw )
1278 : {
1279 166 : poObjRings = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1280 166 : if( NULL == poObjRings )
1281 : {
1282 : CPLError( CE_Failure, CPLE_AppDefined,
1283 : "Invalid Polygon object. "
1284 4 : "Missing \'coordinates\' member." );
1285 4 : return NULL;
1286 : }
1287 : }
1288 : else
1289 : {
1290 32 : poObjRings = poObj;
1291 : }
1292 :
1293 194 : if( json_type_array == json_object_get_type( poObjRings ) )
1294 : {
1295 194 : const int nRings = json_object_array_length( poObjRings );
1296 194 : if( nRings > 0 )
1297 : {
1298 186 : json_object* poObjPoints = NULL;
1299 186 : poObjPoints = json_object_array_get_idx( poObjRings, 0 );
1300 186 : if (poObjPoints == NULL)
1301 : {
1302 8 : poPolygon = new OGRPolygon();
1303 16 : poPolygon->addRingDirectly( new OGRLinearRing() );
1304 : }
1305 : else
1306 : {
1307 178 : OGRLinearRing* poRing = OGRGeoJSONReadLinearRing( poObjPoints );
1308 178 : if( NULL != poRing )
1309 : {
1310 178 : poPolygon = new OGRPolygon();
1311 178 : poPolygon->addRingDirectly( poRing );
1312 : }
1313 : }
1314 :
1315 198 : for( int i = 1; i < nRings && NULL != poPolygon; ++i )
1316 : {
1317 12 : poObjPoints = json_object_array_get_idx( poObjRings, i );
1318 12 : if (poObjPoints == NULL)
1319 : {
1320 4 : poPolygon->addRingDirectly( new OGRLinearRing() );
1321 : }
1322 : else
1323 : {
1324 8 : OGRLinearRing* poRing = OGRGeoJSONReadLinearRing( poObjPoints );
1325 8 : if( NULL != poRing )
1326 : {
1327 8 : poPolygon->addRingDirectly( poRing );
1328 : }
1329 : }
1330 : }
1331 : }
1332 : }
1333 :
1334 194 : return poPolygon;
1335 : }
1336 :
1337 : /************************************************************************/
1338 : /* OGRGeoJSONReadMultiPolygon */
1339 : /************************************************************************/
1340 :
1341 24 : OGRMultiPolygon* OGRGeoJSONReadMultiPolygon( json_object* poObj )
1342 : {
1343 24 : CPLAssert( NULL != poObj );
1344 :
1345 24 : OGRMultiPolygon* poMultiPoly = NULL;
1346 :
1347 24 : json_object* poObjPolys = NULL;
1348 24 : poObjPolys = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1349 24 : if( NULL == poObjPolys )
1350 : {
1351 : CPLError( CE_Failure, CPLE_AppDefined,
1352 : "Invalid MultiPolygon object. "
1353 4 : "Missing \'coordinates\' member." );
1354 4 : return NULL;
1355 : }
1356 :
1357 20 : if( json_type_array == json_object_get_type( poObjPolys ) )
1358 : {
1359 20 : const int nPolys = json_object_array_length( poObjPolys );
1360 :
1361 20 : poMultiPoly = new OGRMultiPolygon();
1362 :
1363 64 : for( int i = 0; i < nPolys; ++i)
1364 : {
1365 :
1366 44 : json_object* poObjPoly = NULL;
1367 44 : poObjPoly = json_object_array_get_idx( poObjPolys, i );
1368 44 : if (poObjPoly == NULL)
1369 : {
1370 12 : poMultiPoly->addGeometryDirectly( new OGRPolygon() );
1371 : }
1372 : else
1373 : {
1374 32 : OGRPolygon* poPoly = OGRGeoJSONReadPolygon( poObjPoly , true );
1375 32 : if( NULL != poPoly )
1376 : {
1377 24 : poMultiPoly->addGeometryDirectly( poPoly );
1378 : }
1379 : }
1380 : }
1381 : }
1382 :
1383 20 : return poMultiPoly;
1384 : }
1385 : /************************************************************************/
1386 : /* OGRGeoJSONReadGeometryCollection */
1387 : /************************************************************************/
1388 :
1389 20 : OGRGeometryCollection* OGRGeoJSONReadGeometryCollection( json_object* poObj )
1390 : {
1391 20 : CPLAssert( NULL != poObj );
1392 :
1393 20 : OGRGeometry* poGeometry = NULL;
1394 20 : OGRGeometryCollection* poCollection = NULL;
1395 :
1396 20 : json_object* poObjGeoms = NULL;
1397 20 : poObjGeoms = OGRGeoJSONFindMemberByName( poObj, "geometries" );
1398 20 : if( NULL == poObjGeoms )
1399 : {
1400 : CPLError( CE_Failure, CPLE_AppDefined,
1401 : "Invalid GeometryCollection object. "
1402 4 : "Missing \'geometries\' member." );
1403 4 : return NULL;
1404 : }
1405 :
1406 16 : if( json_type_array == json_object_get_type( poObjGeoms ) )
1407 : {
1408 16 : const int nGeoms = json_object_array_length( poObjGeoms );
1409 16 : if( nGeoms > 0 )
1410 : {
1411 16 : poCollection = new OGRGeometryCollection();
1412 : }
1413 :
1414 16 : json_object* poObjGeom = NULL;
1415 48 : for( int i = 0; i < nGeoms; ++i )
1416 : {
1417 32 : poObjGeom = json_object_array_get_idx( poObjGeoms, i );
1418 32 : if (poObjGeom == NULL)
1419 : {
1420 12 : CPLDebug( "GeoJSON", "Skipping null sub-geometry");
1421 12 : continue;
1422 : }
1423 :
1424 20 : poGeometry = OGRGeoJSONReadGeometry( poObjGeom );
1425 20 : if( NULL != poGeometry )
1426 : {
1427 20 : poCollection->addGeometryDirectly( poGeometry );
1428 : }
1429 : }
1430 : }
1431 :
1432 16 : return poCollection;
1433 : }
1434 :
1435 : /************************************************************************/
1436 : /* OGR_G_ExportToJson */
1437 : /************************************************************************/
1438 :
1439 0 : OGRGeometryH OGR_G_CreateGeometryFromJson( const char* pszJson )
1440 : {
1441 0 : VALIDATE_POINTER1( pszJson, "OGR_G_CreateGeometryFromJson", NULL );
1442 :
1443 0 : if( NULL != pszJson )
1444 : {
1445 0 : json_tokener* jstok = NULL;
1446 0 : json_object* poObj = NULL;
1447 :
1448 0 : jstok = json_tokener_new();
1449 0 : poObj = json_tokener_parse_ex(jstok, pszJson, -1);
1450 0 : if( jstok->err != json_tokener_success)
1451 : {
1452 : CPLError( CE_Failure, CPLE_AppDefined,
1453 : "GeoJSON parsing error: %s (at offset %d)",
1454 0 : json_tokener_errors[jstok->err], jstok->char_offset);
1455 0 : json_tokener_free(jstok);
1456 0 : return NULL;
1457 : }
1458 0 : json_tokener_free(jstok);
1459 :
1460 0 : OGRGeometry* poGeometry = NULL;
1461 0 : poGeometry = OGRGeoJSONReadGeometry( poObj );
1462 :
1463 : /* Release JSON tree. */
1464 0 : json_object_put( poObj );
1465 :
1466 0 : return (OGRGeometryH)poGeometry;
1467 : }
1468 :
1469 : /* Translation failed */
1470 0 : return NULL;
1471 : }
1472 :
|