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