1 : /******************************************************************************
2 : * $Id: ogrgmllayer.cpp 18077 2009-11-22 19:15:34Z rouault $
3 : *
4 : * Project: OGR
5 : * Purpose: Implements OGRGMLLayer class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
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 :
30 : #include "ogr_gml.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_port.h"
33 : #include "cpl_string.h"
34 : #include "ogr_p.h"
35 :
36 : CPL_CVSID("$Id: ogrgmllayer.cpp 18077 2009-11-22 19:15:34Z rouault $");
37 :
38 : /************************************************************************/
39 : /* OGRGMLLayer() */
40 : /************************************************************************/
41 :
42 17 : OGRGMLLayer::OGRGMLLayer( const char * pszName,
43 : OGRSpatialReference *poSRSIn, int bWriterIn,
44 : OGRwkbGeometryType eReqType,
45 17 : OGRGMLDataSource *poDSIn )
46 :
47 : {
48 17 : if( poSRSIn == NULL )
49 17 : poSRS = NULL;
50 : else
51 0 : poSRS = poSRSIn->Clone();
52 :
53 17 : iNextGMLId = 0;
54 17 : nTotalGMLCount = -1;
55 17 : bInvalidFIDFound = FALSE;
56 17 : pszFIDPrefix = NULL;
57 :
58 17 : poDS = poDSIn;
59 :
60 17 : if ( EQUALN(pszName, "ogr:", 4) )
61 0 : poFeatureDefn = new OGRFeatureDefn( pszName+4 );
62 : else
63 17 : poFeatureDefn = new OGRFeatureDefn( pszName );
64 17 : poFeatureDefn->Reference();
65 17 : poFeatureDefn->SetGeomType( eReqType );
66 :
67 17 : bWriter = bWriterIn;
68 :
69 : /* -------------------------------------------------------------------- */
70 : /* Reader's should get the corresponding GMLFeatureClass and */
71 : /* cache it. */
72 : /* -------------------------------------------------------------------- */
73 17 : if( !bWriter )
74 15 : poFClass = poDS->GetReader()->GetClass( pszName );
75 : else
76 2 : poFClass = NULL;
77 17 : }
78 :
79 : /************************************************************************/
80 : /* ~OGRGMLLayer() */
81 : /************************************************************************/
82 :
83 34 : OGRGMLLayer::~OGRGMLLayer()
84 :
85 : {
86 17 : CPLFree(pszFIDPrefix);
87 :
88 17 : if( poFeatureDefn )
89 17 : poFeatureDefn->Release();
90 :
91 17 : if( poSRS != NULL )
92 0 : poSRS->Release();
93 34 : }
94 :
95 : /************************************************************************/
96 : /* ResetReading() */
97 : /************************************************************************/
98 :
99 16 : void OGRGMLLayer::ResetReading()
100 :
101 : {
102 16 : iNextGMLId = 0;
103 16 : poDS->GetReader()->ResetReading();
104 16 : }
105 :
106 : /************************************************************************/
107 : /* GetNextFeature() */
108 : /************************************************************************/
109 :
110 40 : OGRFeature *OGRGMLLayer::GetNextFeature()
111 :
112 : {
113 40 : GMLFeature *poGMLFeature = NULL;
114 40 : OGRGeometry *poGeom = NULL;
115 :
116 40 : if (bWriter)
117 : {
118 : CPLError(CE_Failure, CPLE_NotSupported,
119 0 : "Cannot read features when writing a GML file");
120 0 : return NULL;
121 : }
122 :
123 40 : if( iNextGMLId == 0 )
124 13 : ResetReading();
125 :
126 : /* ==================================================================== */
127 : /* Loop till we find and translate a feature meeting all our */
128 : /* requirements. */
129 : /* ==================================================================== */
130 2 : while( TRUE )
131 : {
132 : /* -------------------------------------------------------------------- */
133 : /* Cleanup last feature, and get a new raw gml feature. */
134 : /* -------------------------------------------------------------------- */
135 42 : if( poGMLFeature != NULL )
136 2 : delete poGMLFeature;
137 :
138 42 : if( poGeom != NULL )
139 : {
140 1 : delete poGeom;
141 1 : poGeom = NULL;
142 : }
143 :
144 42 : poGMLFeature = poDS->GetReader()->NextFeature();
145 42 : if( poGMLFeature == NULL )
146 9 : return NULL;
147 :
148 : /* -------------------------------------------------------------------- */
149 : /* Is it of the proper feature class? */
150 : /* -------------------------------------------------------------------- */
151 :
152 : // We count reading low level GML features as a feature read for
153 : // work checking purposes, though at least we didn't necessary
154 : // have to turn it into an OGRFeature.
155 33 : m_nFeaturesRead++;
156 :
157 33 : if( poGMLFeature->GetClass() != poFClass )
158 1 : continue;
159 :
160 : /* -------------------------------------------------------------------- */
161 : /* Extract the fid: */
162 : /* -Assumes the fids are non-negative integers with an optional */
163 : /* prefix */
164 : /* -If a prefix differs from the prefix of the first feature from */
165 : /* the poDS then the fids from the poDS are ignored and are */
166 : /* assigned serially thereafter */
167 : /* -------------------------------------------------------------------- */
168 : int nFID;
169 32 : const char * pszGML_FID = poGMLFeature->GetFID();
170 32 : if( bInvalidFIDFound )
171 : {
172 6 : nFID = iNextGMLId++;
173 : }
174 26 : else if( pszGML_FID == NULL )
175 : {
176 1 : bInvalidFIDFound = TRUE;
177 1 : nFID = iNextGMLId++;
178 : }
179 25 : else if( iNextGMLId == 0 )
180 : {
181 12 : int i = strlen( pszGML_FID )-1, j = 0;
182 108 : while( i >= 0 && pszGML_FID[i] >= '0'
183 47 : && pszGML_FID[i] <= '9' && j<8)
184 37 : i--, j++;
185 : /* i points the last character of the fid */
186 12 : if( i >= 0 && j < 8 && pszFIDPrefix == NULL)
187 : {
188 9 : pszFIDPrefix = (char *) CPLMalloc(i+2);
189 9 : pszFIDPrefix[i+1] = '\0';
190 9 : strncpy(pszFIDPrefix, pszGML_FID, i+1);
191 : }
192 : /* pszFIDPrefix now contains the prefix or NULL if no prefix is found */
193 12 : if( j < 8 && sscanf(pszGML_FID+i+1, "%d", &nFID)==1)
194 : {
195 10 : if( iNextGMLId <= nFID )
196 10 : iNextGMLId = nFID + 1;
197 : }
198 : else
199 : {
200 2 : bInvalidFIDFound = TRUE;
201 2 : nFID = iNextGMLId++;
202 : }
203 : }
204 13 : else if( iNextGMLId != 0 )
205 : {
206 13 : const char* pszFIDPrefix_notnull = pszFIDPrefix;
207 13 : if (pszFIDPrefix_notnull == NULL) pszFIDPrefix_notnull = "";
208 13 : int nLenPrefix = strlen(pszFIDPrefix_notnull);
209 :
210 13 : if( strncmp(pszGML_FID, pszFIDPrefix_notnull, nLenPrefix) == 0 &&
211 : strlen(pszGML_FID+nLenPrefix) <= 9 &&
212 : sscanf(pszGML_FID+nLenPrefix, "%d", &nFID) == 1 )
213 : { /* fid with the prefix. Using its numerical part */
214 11 : if( iNextGMLId < nFID )
215 5 : iNextGMLId = nFID + 1;
216 : }
217 : else
218 : { /* fid without the aforementioned prefix or a valid numerical part */
219 2 : bInvalidFIDFound = TRUE;
220 2 : nFID = iNextGMLId++;
221 : }
222 : }
223 :
224 : /* -------------------------------------------------------------------- */
225 : /* Does it satisfy the spatial query, if there is one? */
226 : /* -------------------------------------------------------------------- */
227 :
228 32 : if( poGMLFeature->GetGeometry() != NULL )
229 : {
230 30 : poGeom = OGRGeometryFactory::createFromGML( poGMLFeature->GetGeometry() );
231 : // We assume the createFromGML() function would have already
232 : // reported the error.
233 30 : if( poGeom == NULL )
234 : {
235 0 : delete poGMLFeature;
236 0 : return NULL;
237 : }
238 :
239 30 : if( m_poFilterGeom != NULL && !FilterGeometry( poGeom ) )
240 0 : continue;
241 : }
242 :
243 : /* -------------------------------------------------------------------- */
244 : /* Convert the whole feature into an OGRFeature. */
245 : /* -------------------------------------------------------------------- */
246 : int iField;
247 32 : OGRFeature *poOGRFeature = new OGRFeature( GetLayerDefn() );
248 :
249 32 : poOGRFeature->SetFID( nFID );
250 :
251 141 : for( iField = 0; iField < poFClass->GetPropertyCount(); iField++ )
252 : {
253 109 : const char *pszProperty = poGMLFeature->GetProperty( iField );
254 :
255 109 : if( pszProperty != NULL )
256 106 : poOGRFeature->SetField( iField, pszProperty );
257 : }
258 :
259 : /* -------------------------------------------------------------------- */
260 : /* Test against the attribute query. */
261 : /* -------------------------------------------------------------------- */
262 32 : if( m_poAttrQuery != NULL
263 : && !m_poAttrQuery->Evaluate( poOGRFeature ) )
264 : {
265 1 : delete poOGRFeature;
266 1 : continue;
267 : }
268 :
269 : /* -------------------------------------------------------------------- */
270 : /* Wow, we got our desired feature. Return it. */
271 : /* -------------------------------------------------------------------- */
272 31 : delete poGMLFeature;
273 :
274 31 : poOGRFeature->SetGeometryDirectly( poGeom );
275 :
276 31 : return poOGRFeature;
277 : }
278 :
279 : return NULL;
280 : }
281 :
282 : /************************************************************************/
283 : /* GetFeatureCount() */
284 : /************************************************************************/
285 :
286 2 : int OGRGMLLayer::GetFeatureCount( int bForce )
287 :
288 : {
289 2 : if( poFClass == NULL )
290 0 : return 0;
291 :
292 2 : if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
293 0 : return OGRLayer::GetFeatureCount( bForce );
294 : else
295 : {
296 : /* If the schema is read from a .xsd file, we haven't read */
297 : /* the feature count, so compute it now */
298 2 : int nFeatureCount = poFClass->GetFeatureCount();
299 2 : if (nFeatureCount < 0)
300 : {
301 1 : nFeatureCount = OGRLayer::GetFeatureCount(bForce);
302 1 : poFClass->SetFeatureCount(nFeatureCount);
303 : }
304 2 : return nFeatureCount;
305 : }
306 : }
307 :
308 : /************************************************************************/
309 : /* GetExtent() */
310 : /************************************************************************/
311 :
312 0 : OGRErr OGRGMLLayer::GetExtent(OGREnvelope *psExtent, int bForce )
313 :
314 : {
315 : double dfXMin, dfXMax, dfYMin, dfYMax;
316 :
317 0 : if( poFClass != NULL &&
318 : poFClass->GetExtents( &dfXMin, &dfXMax, &dfYMin, &dfYMax ) )
319 : {
320 0 : psExtent->MinX = dfXMin;
321 0 : psExtent->MaxX = dfXMax;
322 0 : psExtent->MinY = dfYMin;
323 0 : psExtent->MaxY = dfYMax;
324 :
325 0 : return OGRERR_NONE;
326 : }
327 : else
328 0 : return OGRLayer::GetExtent( psExtent, bForce );
329 : }
330 :
331 : /************************************************************************/
332 : /* CreateFeature() */
333 : /************************************************************************/
334 :
335 2 : OGRErr OGRGMLLayer::CreateFeature( OGRFeature *poFeature )
336 :
337 : {
338 2 : FILE *fp = poDS->GetOutputFP();
339 :
340 2 : if( !bWriter )
341 0 : return OGRERR_FAILURE;
342 :
343 2 : VSIFPrintf( fp, " <gml:featureMember>\n" );
344 :
345 2 : if( poFeature->GetFID() == OGRNullFID )
346 2 : poFeature->SetFID( iNextGMLId++ );
347 :
348 : VSIFPrintf( fp, " <ogr:%s fid=\"F%ld\">\n",
349 : poFeatureDefn->GetName(),
350 2 : poFeature->GetFID() );
351 :
352 : // Write out Geometry - for now it isn't indented properly.
353 2 : if( poFeature->GetGeometryRef() != NULL )
354 : {
355 : char *pszGeometry;
356 0 : OGREnvelope sGeomBounds;
357 :
358 0 : pszGeometry = poFeature->GetGeometryRef()->exportToGML();
359 : VSIFPrintf( fp, " <ogr:geometryProperty>%s</ogr:geometryProperty>\n",
360 0 : pszGeometry );
361 0 : CPLFree( pszGeometry );
362 :
363 0 : poFeature->GetGeometryRef()->getEnvelope( &sGeomBounds );
364 0 : poDS->GrowExtents( &sGeomBounds );
365 : }
366 :
367 : // Write all "set" fields.
368 8 : for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
369 : {
370 :
371 6 : OGRFieldDefn *poField = poFeatureDefn->GetFieldDefn( iField );
372 :
373 6 : if( poFeature->IsFieldSet( iField ) )
374 : {
375 6 : const char *pszRaw = poFeature->GetFieldAsString( iField );
376 :
377 12 : while( *pszRaw == ' ' )
378 0 : pszRaw++;
379 :
380 6 : char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
381 : VSIFPrintf( fp, " <ogr:%s>%s</ogr:%s>\n",
382 : poField->GetNameRef(), pszEscaped,
383 6 : poField->GetNameRef() );
384 6 : CPLFree( pszEscaped );
385 : }
386 : }
387 :
388 2 : VSIFPrintf( fp, " </ogr:%s>\n", poFeatureDefn->GetName() );
389 2 : VSIFPrintf( fp, " </gml:featureMember>\n" );
390 :
391 2 : return OGRERR_NONE;
392 : }
393 :
394 : /************************************************************************/
395 : /* TestCapability() */
396 : /************************************************************************/
397 :
398 0 : int OGRGMLLayer::TestCapability( const char * pszCap )
399 :
400 : {
401 0 : if( EQUAL(pszCap,OLCSequentialWrite) )
402 0 : return bWriter;
403 :
404 0 : else if( EQUAL(pszCap,OLCCreateField) )
405 0 : return bWriter && iNextGMLId == 0;
406 :
407 0 : else if( EQUAL(pszCap,OLCFastGetExtent) )
408 : {
409 : double dfXMin, dfXMax, dfYMin, dfYMax;
410 :
411 0 : if( poFClass == NULL )
412 0 : return FALSE;
413 :
414 0 : return poFClass->GetExtents( &dfXMin, &dfXMax, &dfYMin, &dfYMax );
415 : }
416 :
417 0 : else if( EQUAL(pszCap,OLCFastFeatureCount) )
418 : {
419 0 : if( poFClass == NULL
420 : || m_poFilterGeom != NULL
421 : || m_poAttrQuery != NULL )
422 0 : return FALSE;
423 :
424 0 : return poFClass->GetFeatureCount() != -1;
425 : }
426 :
427 0 : else if( EQUAL(pszCap,OLCStringsAsUTF8) )
428 0 : return TRUE;
429 :
430 : else
431 0 : return FALSE;
432 : }
433 :
434 : /************************************************************************/
435 : /* CreateField() */
436 : /************************************************************************/
437 :
438 6 : OGRErr OGRGMLLayer::CreateField( OGRFieldDefn *poField, int bApproxOK )
439 :
440 : {
441 6 : if( !bWriter || iNextGMLId != 0 )
442 0 : return OGRERR_FAILURE;
443 :
444 : /* -------------------------------------------------------------------- */
445 : /* Enforce XML naming semantics on element name. */
446 : /* -------------------------------------------------------------------- */
447 6 : OGRFieldDefn oCleanCopy( poField );
448 6 : char *pszName = CPLStrdup( poField->GetNameRef() );
449 6 : CPLCleanXMLElementName( pszName );
450 :
451 6 : if( strcmp(pszName,poField->GetNameRef()) != 0 )
452 : {
453 0 : if( !bApproxOK )
454 : {
455 0 : CPLFree( pszName );
456 : CPLError( CE_Failure, CPLE_AppDefined,
457 : "Unable to create field with name '%s', it would not\n"
458 : "be valid as an XML element name.",
459 0 : poField->GetNameRef() );
460 0 : return OGRERR_FAILURE;
461 : }
462 :
463 0 : oCleanCopy.SetName( pszName );
464 : CPLError( CE_Warning, CPLE_AppDefined,
465 : "Field name '%s' adjusted to '%s' to be a valid\n"
466 : "XML element name.",
467 0 : poField->GetNameRef(), pszName );
468 : }
469 :
470 6 : CPLFree( pszName );
471 :
472 :
473 6 : poFeatureDefn->AddFieldDefn( &oCleanCopy );
474 :
475 6 : return OGRERR_NONE;
476 : }
477 :
478 : /************************************************************************/
479 : /* GetSpatialRef() */
480 : /************************************************************************/
481 :
482 0 : OGRSpatialReference *OGRGMLLayer::GetSpatialRef()
483 :
484 : {
485 0 : return poSRS;
486 : }
487 :
|