1 : /**********************************************************************
2 : * $Id: gmlfeatureclass.cpp 22954 2011-08-19 21:47:19Z rouault $
3 : *
4 : * Project: GML Reader
5 : * Purpose: Implementation of GMLFeatureClass.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : **********************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam
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 OR
22 : * 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 "gmlreader.h"
31 : #include "cpl_conv.h"
32 : #include "ogr_core.h"
33 :
34 : /************************************************************************/
35 : /* GMLFeatureClass() */
36 : /************************************************************************/
37 :
38 301 : GMLFeatureClass::GMLFeatureClass( const char *pszName )
39 :
40 : {
41 301 : m_pszName = CPLStrdup( pszName );
42 301 : n_nNameLen = strlen( m_pszName );
43 301 : m_pszElementName = NULL;
44 301 : n_nElementNameLen = 0;
45 301 : m_pszGeometryElement = NULL;
46 301 : m_nPropertyCount = 0;
47 301 : m_papoProperty = NULL;
48 301 : m_bSchemaLocked = FALSE;
49 :
50 301 : m_pszExtraInfo = NULL;
51 301 : m_bHaveExtents = FALSE;
52 301 : m_nFeatureCount = -1; // unknown
53 :
54 301 : m_nGeometryType = 0; // wkbUnknown
55 301 : m_nGeometryIndex = -1;
56 :
57 301 : m_pszSRSName = NULL;
58 301 : m_bSRSNameConsistant = TRUE;
59 301 : }
60 :
61 : /************************************************************************/
62 : /* ~GMLFeatureClass() */
63 : /************************************************************************/
64 :
65 301 : GMLFeatureClass::~GMLFeatureClass()
66 :
67 : {
68 301 : CPLFree( m_pszName );
69 301 : CPLFree( m_pszElementName );
70 301 : CPLFree( m_pszGeometryElement );
71 :
72 2098 : for( int i = 0; i < m_nPropertyCount; i++ )
73 1797 : delete m_papoProperty[i];
74 301 : CPLFree( m_papoProperty );
75 301 : CPLFree( m_pszSRSName );
76 301 : }
77 :
78 : /************************************************************************/
79 : /* GetProperty(int) */
80 : /************************************************************************/
81 :
82 822827 : GMLPropertyDefn *GMLFeatureClass::GetProperty( int iIndex ) const
83 :
84 : {
85 822827 : if( iIndex < 0 || iIndex >= m_nPropertyCount )
86 1900 : return NULL;
87 : else
88 820927 : return m_papoProperty[iIndex];
89 : }
90 :
91 : /************************************************************************/
92 : /* GetPropertyIndex() */
93 : /************************************************************************/
94 :
95 3756 : int GMLFeatureClass::GetPropertyIndex( const char *pszName ) const
96 :
97 : {
98 15393 : for( int i = 0; i < m_nPropertyCount; i++ )
99 13476 : if( EQUAL(pszName,m_papoProperty[i]->GetName()) )
100 1839 : return i;
101 :
102 1917 : return -1;
103 : }
104 :
105 : /************************************************************************/
106 : /* GetPropertyIndexBySrcElement() */
107 : /************************************************************************/
108 :
109 1634 : int GMLFeatureClass::GetPropertyIndexBySrcElement( const char *pszElement, int nLen ) const
110 :
111 : {
112 4391 : for( int i = 0; i < m_nPropertyCount; i++ )
113 5524 : if( nLen == (int)m_papoProperty[i]->GetSrcElementLen() &&
114 1620 : memcmp(pszElement,m_papoProperty[i]->GetSrcElement(), nLen) == 0)
115 1147 : return i;
116 :
117 487 : return -1;
118 : }
119 :
120 :
121 :
122 : /************************************************************************/
123 : /* AddProperty() */
124 : /************************************************************************/
125 :
126 1797 : int GMLFeatureClass::AddProperty( GMLPropertyDefn *poDefn )
127 :
128 : {
129 1797 : if( GetProperty(poDefn->GetName()) != NULL )
130 : {
131 : CPLError(CE_Warning, CPLE_AppDefined,
132 : "Field with same name (%s) already exists. Skipping newer ones",
133 0 : poDefn->GetName());
134 0 : return -1;
135 : }
136 :
137 1797 : m_nPropertyCount++;
138 : m_papoProperty = (GMLPropertyDefn **)
139 1797 : CPLRealloc( m_papoProperty, sizeof(void*) * m_nPropertyCount );
140 :
141 1797 : m_papoProperty[m_nPropertyCount-1] = poDefn;
142 :
143 1797 : return m_nPropertyCount-1;
144 : }
145 :
146 : /************************************************************************/
147 : /* SetElementName() */
148 : /************************************************************************/
149 :
150 148 : void GMLFeatureClass::SetElementName( const char *pszElementName )
151 :
152 : {
153 148 : CPLFree( m_pszElementName );
154 148 : m_pszElementName = CPLStrdup( pszElementName );
155 148 : n_nElementNameLen = strlen(pszElementName);
156 148 : }
157 :
158 : /************************************************************************/
159 : /* GetElementName() */
160 : /************************************************************************/
161 :
162 1250857 : const char *GMLFeatureClass::GetElementName() const
163 :
164 : {
165 1250857 : if( m_pszElementName == NULL )
166 1186 : return m_pszName;
167 : else
168 1249671 : return m_pszElementName;
169 : }
170 :
171 : /************************************************************************/
172 : /* GetElementName() */
173 : /************************************************************************/
174 :
175 598 : size_t GMLFeatureClass::GetElementNameLen() const
176 :
177 : {
178 598 : if( m_pszElementName == NULL )
179 431 : return n_nNameLen;
180 : else
181 167 : return n_nElementNameLen;
182 : }
183 :
184 : /************************************************************************/
185 : /* SetGeometryElement() */
186 : /************************************************************************/
187 :
188 119 : void GMLFeatureClass::SetGeometryElement( const char *pszElement )
189 :
190 : {
191 119 : CPLFree( m_pszGeometryElement );
192 119 : if (pszElement)
193 110 : m_pszGeometryElement = CPLStrdup( pszElement );
194 : else
195 9 : m_pszGeometryElement = NULL;
196 119 : }
197 :
198 : /************************************************************************/
199 : /* GetFeatureCount() */
200 : /************************************************************************/
201 :
202 868 : int GMLFeatureClass::GetFeatureCount()
203 :
204 : {
205 868 : return m_nFeatureCount;
206 : }
207 :
208 : /************************************************************************/
209 : /* SetFeatureCount() */
210 : /************************************************************************/
211 :
212 381 : void GMLFeatureClass::SetFeatureCount( int nNewCount )
213 :
214 : {
215 381 : m_nFeatureCount = nNewCount;
216 381 : }
217 :
218 : /************************************************************************/
219 : /* GetExtraInfo() */
220 : /************************************************************************/
221 :
222 0 : const char *GMLFeatureClass::GetExtraInfo()
223 :
224 : {
225 0 : return m_pszExtraInfo;
226 : }
227 :
228 : /************************************************************************/
229 : /* SetExtraInfo() */
230 : /************************************************************************/
231 :
232 0 : void GMLFeatureClass::SetExtraInfo( const char *pszExtraInfo )
233 :
234 : {
235 0 : CPLFree( m_pszExtraInfo );
236 0 : m_pszExtraInfo = NULL;
237 :
238 0 : if( pszExtraInfo != NULL )
239 0 : m_pszExtraInfo = CPLStrdup( pszExtraInfo );
240 0 : }
241 :
242 : /************************************************************************/
243 : /* SetExtents() */
244 : /************************************************************************/
245 :
246 322 : void GMLFeatureClass::SetExtents( double dfXMin, double dfXMax,
247 : double dfYMin, double dfYMax )
248 :
249 : {
250 322 : m_dfXMin = dfXMin;
251 322 : m_dfXMax = dfXMax;
252 322 : m_dfYMin = dfYMin;
253 322 : m_dfYMax = dfYMax;
254 :
255 322 : m_bHaveExtents = TRUE;
256 322 : }
257 :
258 : /************************************************************************/
259 : /* GetExtents() */
260 : /************************************************************************/
261 :
262 210 : int GMLFeatureClass::GetExtents( double *pdfXMin, double *pdfXMax,
263 : double *pdfYMin, double *pdfYMax )
264 :
265 : {
266 210 : if( m_bHaveExtents )
267 : {
268 180 : *pdfXMin = m_dfXMin;
269 180 : *pdfXMax = m_dfXMax;
270 180 : *pdfYMin = m_dfYMin;
271 180 : *pdfYMax = m_dfYMax;
272 : }
273 :
274 210 : return m_bHaveExtents;
275 : }
276 :
277 : /************************************************************************/
278 : /* SetSRSName() */
279 : /************************************************************************/
280 :
281 154 : void GMLFeatureClass::SetSRSName( const char* pszSRSName )
282 :
283 : {
284 154 : m_bSRSNameConsistant = TRUE;
285 154 : CPLFree(m_pszSRSName);
286 154 : m_pszSRSName = (pszSRSName) ? CPLStrdup(pszSRSName) : NULL;
287 154 : }
288 :
289 : /************************************************************************/
290 : /* MergeSRSName() */
291 : /************************************************************************/
292 :
293 205 : void GMLFeatureClass::MergeSRSName( const char* pszSRSName )
294 :
295 : {
296 205 : if(!m_bSRSNameConsistant)
297 0 : return;
298 :
299 205 : if( m_pszSRSName == NULL )
300 : {
301 110 : if (pszSRSName)
302 12 : m_pszSRSName = CPLStrdup(pszSRSName);
303 : }
304 : else
305 : {
306 : m_bSRSNameConsistant = pszSRSName != NULL &&
307 95 : strcmp(m_pszSRSName, pszSRSName) == 0;
308 95 : if (!m_bSRSNameConsistant)
309 : {
310 0 : CPLFree(m_pszSRSName);
311 0 : m_pszSRSName = NULL;
312 : }
313 : }
314 : }
315 :
316 : /************************************************************************/
317 : /* InitializeFromXML() */
318 : /************************************************************************/
319 :
320 148 : int GMLFeatureClass::InitializeFromXML( CPLXMLNode *psRoot )
321 :
322 : {
323 : /* -------------------------------------------------------------------- */
324 : /* Do some rudimentary checking that this is a well formed */
325 : /* node. */
326 : /* -------------------------------------------------------------------- */
327 148 : if( psRoot == NULL
328 : || psRoot->eType != CXT_Element
329 : || !EQUAL(psRoot->pszValue,"GMLFeatureClass") )
330 : {
331 : CPLError( CE_Failure, CPLE_AppDefined,
332 : "GMLFeatureClass::InitializeFromXML() called on %s node!",
333 0 : psRoot->pszValue );
334 0 : return FALSE;
335 : }
336 :
337 148 : if( CPLGetXMLValue( psRoot, "Name", NULL ) == NULL )
338 : {
339 : CPLError( CE_Failure, CPLE_AppDefined,
340 0 : "GMLFeatureClass has no <Name> element." );
341 0 : return FALSE;
342 : }
343 :
344 : /* -------------------------------------------------------------------- */
345 : /* Collect base info. */
346 : /* -------------------------------------------------------------------- */
347 148 : CPLFree( m_pszName );
348 148 : m_pszName = CPLStrdup( CPLGetXMLValue( psRoot, "Name", NULL ) );
349 148 : n_nNameLen = strlen(m_pszName);
350 :
351 148 : SetElementName( CPLGetXMLValue( psRoot, "ElementPath", m_pszName ) );
352 :
353 148 : const char *pszGPath = CPLGetXMLValue( psRoot, "GeometryElementPath", "" );
354 :
355 148 : if( strlen( pszGPath ) > 0 )
356 2 : SetGeometryElement( pszGPath );
357 :
358 148 : const char* pszGeometryType = CPLGetXMLValue( psRoot, "GeometryType", NULL );
359 148 : if( pszGeometryType != NULL )
360 : {
361 126 : int nGeomType = atoi(pszGeometryType) & (~wkb25DBit);
362 252 : if ((nGeomType >= 0 && nGeomType <= 7) || nGeomType == 100)
363 126 : SetGeometryType( atoi(pszGeometryType) );
364 : else
365 : {
366 : CPLError(CE_Warning, CPLE_AppDefined, "Unrecognised geometry type : %s",
367 0 : pszGeometryType);
368 : }
369 : }
370 :
371 148 : SetSRSName( CPLGetXMLValue( psRoot, "SRSName", NULL ) );
372 :
373 : /* -------------------------------------------------------------------- */
374 : /* Collect dataset specific info. */
375 : /* -------------------------------------------------------------------- */
376 148 : CPLXMLNode *psDSI = CPLGetXMLNode( psRoot, "DatasetSpecificInfo" );
377 148 : if( psDSI != NULL )
378 : {
379 : const char *pszValue;
380 :
381 146 : pszValue = CPLGetXMLValue( psDSI, "FeatureCount", NULL );
382 146 : if( pszValue != NULL )
383 146 : SetFeatureCount( atoi(pszValue) );
384 :
385 : // Eventually we should support XML subtrees.
386 146 : pszValue = CPLGetXMLValue( psDSI, "ExtraInfo", NULL );
387 146 : if( pszValue != NULL )
388 0 : SetExtraInfo( pszValue );
389 :
390 146 : if( CPLGetXMLValue( psDSI, "ExtentXMin", NULL ) != NULL
391 : && CPLGetXMLValue( psDSI, "ExtentXMax", NULL ) != NULL
392 : && CPLGetXMLValue( psDSI, "ExtentYMin", NULL ) != NULL
393 : && CPLGetXMLValue( psDSI, "ExtentYMax", NULL ) != NULL )
394 : {
395 : SetExtents( CPLAtof(CPLGetXMLValue( psDSI, "ExtentXMin", "0.0" )),
396 : CPLAtof(CPLGetXMLValue( psDSI, "ExtentXMax", "0.0" )),
397 : CPLAtof(CPLGetXMLValue( psDSI, "ExtentYMin", "0.0" )),
398 116 : CPLAtof(CPLGetXMLValue( psDSI, "ExtentYMax", "0.0" )) );
399 : }
400 : }
401 :
402 : /* -------------------------------------------------------------------- */
403 : /* Collect property definitions. */
404 : /* -------------------------------------------------------------------- */
405 1739 : for( CPLXMLNode *psThis = psRoot->psChild;
406 : psThis != NULL; psThis = psThis->psNext )
407 : {
408 1591 : if( EQUAL(psThis->pszValue, "PropertyDefn") )
409 : {
410 1013 : const char *pszName = CPLGetXMLValue( psThis, "Name", NULL );
411 1013 : const char *pszType = CPLGetXMLValue( psThis, "Type", "Untyped" );
412 : GMLPropertyDefn *poPDefn;
413 :
414 1013 : if( pszName == NULL )
415 : {
416 : CPLError( CE_Failure, CPLE_AppDefined,
417 : "GMLFeatureClass %s has a PropertyDefn without a <Name>..",
418 0 : m_pszName );
419 0 : return FALSE;
420 : }
421 :
422 : poPDefn = new GMLPropertyDefn(
423 1013 : pszName, CPLGetXMLValue( psThis, "ElementPath", NULL ) );
424 :
425 1013 : if( EQUAL(pszType,"Untyped") )
426 32 : poPDefn->SetType( GMLPT_Untyped );
427 981 : else if( EQUAL(pszType,"String") )
428 : {
429 589 : poPDefn->SetType( GMLPT_String );
430 589 : poPDefn->SetWidth( atoi( CPLGetXMLValue( psThis, "Width", "0" ) ) );
431 : }
432 392 : else if( EQUAL(pszType,"Integer") )
433 : {
434 357 : poPDefn->SetType( GMLPT_Integer );
435 357 : poPDefn->SetWidth( atoi( CPLGetXMLValue( psThis, "Width", "0" ) ) );
436 : }
437 35 : else if( EQUAL(pszType,"Real") )
438 : {
439 11 : poPDefn->SetType( GMLPT_Real );
440 11 : poPDefn->SetWidth( atoi( CPLGetXMLValue( psThis, "Width", "0" ) ) );
441 11 : poPDefn->SetPrecision( atoi( CPLGetXMLValue( psThis, "Precision", "0" ) ) );
442 : }
443 24 : else if( EQUAL(pszType,"StringList") )
444 14 : poPDefn->SetType( GMLPT_StringList );
445 10 : else if( EQUAL(pszType,"IntegerList") )
446 7 : poPDefn->SetType( GMLPT_IntegerList );
447 3 : else if( EQUAL(pszType,"RealList") )
448 3 : poPDefn->SetType( GMLPT_RealList );
449 0 : else if( EQUAL(pszType,"Complex") )
450 0 : poPDefn->SetType( GMLPT_Complex );
451 : else
452 : {
453 : CPLError( CE_Failure, CPLE_AppDefined,
454 : "Unrecognised property type %s.",
455 0 : pszType );
456 0 : delete poPDefn;
457 0 : return FALSE;
458 : }
459 :
460 1013 : AddProperty( poPDefn );
461 : }
462 : }
463 :
464 148 : return TRUE;
465 : }
466 :
467 : /************************************************************************/
468 : /* SerializeToXML() */
469 : /************************************************************************/
470 :
471 31 : CPLXMLNode *GMLFeatureClass::SerializeToXML()
472 :
473 : {
474 : CPLXMLNode *psRoot;
475 : int iProperty;
476 :
477 : /* -------------------------------------------------------------------- */
478 : /* Set feature class and core information. */
479 : /* -------------------------------------------------------------------- */
480 31 : psRoot = CPLCreateXMLNode( NULL, CXT_Element, "GMLFeatureClass" );
481 :
482 31 : CPLCreateXMLElementAndValue( psRoot, "Name", GetName() );
483 31 : CPLCreateXMLElementAndValue( psRoot, "ElementPath", GetElementName() );
484 31 : if( GetGeometryElement() != NULL && strlen(GetGeometryElement()) > 0 )
485 : CPLCreateXMLElementAndValue( psRoot, "GeometryElementPath",
486 0 : GetGeometryElement() );
487 :
488 31 : if( GetGeometryType() != 0 /* wkbUnknown */ )
489 : {
490 : char szValue[128];
491 :
492 29 : sprintf( szValue, "%d", GetGeometryType() );
493 29 : CPLCreateXMLElementAndValue( psRoot, "GeometryType", szValue );
494 : }
495 :
496 31 : const char* pszSRSName = GetSRSName();
497 31 : if( pszSRSName )
498 : {
499 13 : CPLCreateXMLElementAndValue( psRoot, "SRSName", pszSRSName );
500 : }
501 :
502 : /* -------------------------------------------------------------------- */
503 : /* Write out dataset specific information. */
504 : /* -------------------------------------------------------------------- */
505 : CPLXMLNode *psDSI;
506 :
507 31 : if( m_bHaveExtents || m_nFeatureCount != -1 || m_pszExtraInfo != NULL )
508 : {
509 31 : psDSI = CPLCreateXMLNode( psRoot, CXT_Element, "DatasetSpecificInfo" );
510 :
511 31 : if( m_nFeatureCount != -1 )
512 : {
513 : char szValue[128];
514 :
515 31 : sprintf( szValue, "%d", m_nFeatureCount );
516 31 : CPLCreateXMLElementAndValue( psDSI, "FeatureCount", szValue );
517 : }
518 :
519 31 : if( m_bHaveExtents )
520 : {
521 : char szValue[128];
522 :
523 27 : sprintf( szValue, "%.5f", m_dfXMin );
524 27 : CPLCreateXMLElementAndValue( psDSI, "ExtentXMin", szValue );
525 :
526 27 : sprintf( szValue, "%.5f", m_dfXMax );
527 27 : CPLCreateXMLElementAndValue( psDSI, "ExtentXMax", szValue );
528 :
529 27 : sprintf( szValue, "%.5f", m_dfYMin );
530 27 : CPLCreateXMLElementAndValue( psDSI, "ExtentYMin", szValue );
531 :
532 27 : sprintf( szValue, "%.5f", m_dfYMax );
533 27 : CPLCreateXMLElementAndValue( psDSI, "ExtentYMax", szValue );
534 : }
535 :
536 31 : if( m_pszExtraInfo )
537 0 : CPLCreateXMLElementAndValue( psDSI, "ExtraInfo", m_pszExtraInfo );
538 : }
539 :
540 : /* -------------------------------------------------------------------- */
541 : /* emit property information. */
542 : /* -------------------------------------------------------------------- */
543 130 : for( iProperty = 0; iProperty < GetPropertyCount(); iProperty++ )
544 : {
545 99 : GMLPropertyDefn *poPDefn = GetProperty( iProperty );
546 : CPLXMLNode *psPDefnNode;
547 99 : const char *pszTypeName = "Unknown";
548 :
549 99 : psPDefnNode = CPLCreateXMLNode( psRoot, CXT_Element, "PropertyDefn" );
550 : CPLCreateXMLElementAndValue( psPDefnNode, "Name",
551 99 : poPDefn->GetName() );
552 : CPLCreateXMLElementAndValue( psPDefnNode, "ElementPath",
553 99 : poPDefn->GetSrcElement() );
554 99 : switch( poPDefn->GetType() )
555 : {
556 : case GMLPT_Untyped:
557 2 : pszTypeName = "Untyped";
558 2 : break;
559 :
560 : case GMLPT_String:
561 45 : pszTypeName = "String";
562 45 : break;
563 :
564 : case GMLPT_Integer:
565 38 : pszTypeName = "Integer";
566 38 : break;
567 :
568 : case GMLPT_Real:
569 9 : pszTypeName = "Real";
570 9 : break;
571 :
572 : case GMLPT_Complex:
573 0 : pszTypeName = "Complex";
574 0 : break;
575 :
576 : case GMLPT_IntegerList:
577 0 : pszTypeName = "IntegerList";
578 0 : break;
579 :
580 : case GMLPT_RealList:
581 0 : pszTypeName = "RealList";
582 0 : break;
583 :
584 : case GMLPT_StringList:
585 5 : pszTypeName = "StringList";
586 : break;
587 : }
588 99 : CPLCreateXMLElementAndValue( psPDefnNode, "Type", pszTypeName );
589 :
590 99 : if( EQUAL(pszTypeName,"String") )
591 : {
592 : char szMaxLength[48];
593 45 : sprintf(szMaxLength, "%d", poPDefn->GetWidth());
594 45 : CPLCreateXMLElementAndValue ( psPDefnNode, "Width", szMaxLength );
595 : }
596 99 : if( poPDefn->GetWidth() > 0 && EQUAL(pszTypeName,"Integer") )
597 : {
598 : char szLength[48];
599 0 : sprintf(szLength, "%d", poPDefn->GetWidth());
600 0 : CPLCreateXMLElementAndValue ( psPDefnNode, "Width", szLength );
601 : }
602 99 : if( poPDefn->GetWidth() > 0 && EQUAL(pszTypeName,"Real") )
603 : {
604 : char szLength[48];
605 0 : sprintf(szLength, "%d", poPDefn->GetWidth());
606 0 : CPLCreateXMLElementAndValue ( psPDefnNode, "Width", szLength );
607 : char szPrecision[48];
608 0 : sprintf(szPrecision, "%d", poPDefn->GetPrecision());
609 0 : CPLCreateXMLElementAndValue ( psPDefnNode, "Precision", szPrecision );
610 : }
611 : }
612 :
613 31 : return psRoot;
614 : }
615 :
|