1 : /******************************************************************************
2 : * $Id: gmlreader.cpp 18190 2009-12-06 05:25:31Z chaitanya $
3 : *
4 : * Project: GML Reader
5 : * Purpose: Implementation of GMLReader class.
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_error.h"
32 :
33 : #define SUPPORT_GEOMETRY
34 :
35 : #ifdef SUPPORT_GEOMETRY
36 : # include "ogr_geometry.h"
37 : #endif
38 :
39 : /************************************************************************/
40 : /* ~IGMLReader() */
41 : /************************************************************************/
42 :
43 17 : IGMLReader::~IGMLReader()
44 :
45 : {
46 17 : }
47 :
48 : /************************************************************************/
49 : /* ==================================================================== */
50 : /* No XERCES or EXPAT Library */
51 : /* ==================================================================== */
52 : /************************************************************************/
53 : #if HAVE_XERCES == 0 && !defined(HAVE_EXPAT)
54 :
55 : /************************************************************************/
56 : /* CreateGMLReader() */
57 : /************************************************************************/
58 :
59 : IGMLReader *CreateGMLReader()
60 :
61 : {
62 : CPLError( CE_Failure, CPLE_AppDefined,
63 : "Unable to create Xerces C++ or Expat based GML reader, Xerces or Expat support\n"
64 : "not configured into GDAL/OGR." );
65 : return NULL;
66 : }
67 :
68 : /************************************************************************/
69 : /* ==================================================================== */
70 : /* With XERCES or EXPAT Library */
71 : /* ==================================================================== */
72 : /************************************************************************/
73 : #else /* HAVE_XERCES == 1 or HAVE_EXPAT */
74 :
75 : #include "gmlreaderp.h"
76 : #include "cpl_conv.h"
77 :
78 : /************************************************************************/
79 : /* CreateGMLReader() */
80 : /************************************************************************/
81 :
82 17 : IGMLReader *CreateGMLReader()
83 :
84 : {
85 17 : return new GMLReader();
86 : }
87 :
88 : int GMLReader::m_bXercesInitialized = FALSE;
89 : int GMLReader::m_nInstanceCount = 0;
90 :
91 : /************************************************************************/
92 : /* GMLReader() */
93 : /************************************************************************/
94 :
95 17 : GMLReader::GMLReader()
96 :
97 : {
98 17 : m_nInstanceCount++;
99 17 : m_nClassCount = 0;
100 17 : m_papoClass = NULL;
101 :
102 17 : m_bClassListLocked = FALSE;
103 :
104 17 : m_poGMLHandler = NULL;
105 : #if HAVE_XERCES == 1
106 : m_poSAXReader = NULL;
107 : m_poCompleteFeature = NULL;
108 : #else
109 17 : oParser = NULL;
110 17 : ppoFeatureTab = NULL;
111 17 : nFeatureTabIndex = 0;
112 17 : nFeatureTabLength = 0;
113 17 : fpGML = NULL;
114 : #endif
115 17 : m_bReadStarted = FALSE;
116 :
117 17 : m_poState = NULL;
118 :
119 17 : m_pszFilename = NULL;
120 :
121 17 : m_bStopParsing = FALSE;
122 17 : }
123 :
124 : /************************************************************************/
125 : /* ~GMLReader() */
126 : /************************************************************************/
127 :
128 34 : GMLReader::~GMLReader()
129 :
130 : {
131 17 : ClearClasses();
132 :
133 17 : CPLFree( m_pszFilename );
134 :
135 17 : CleanupParser();
136 :
137 17 : --m_nInstanceCount;
138 : #if HAVE_XERCES == 1
139 : if( m_nInstanceCount == 0 && m_bXercesInitialized )
140 : {
141 : XMLPlatformUtils::Terminate();
142 : m_bXercesInitialized = FALSE;
143 : }
144 : #endif
145 :
146 : #ifdef HAVE_EXPAT
147 17 : if (fpGML)
148 16 : VSIFCloseL(fpGML);
149 17 : fpGML = NULL;
150 : #endif
151 34 : }
152 :
153 : /************************************************************************/
154 : /* SetSource() */
155 : /************************************************************************/
156 :
157 17 : void GMLReader::SetSourceFile( const char *pszFilename )
158 :
159 : {
160 17 : CPLFree( m_pszFilename );
161 17 : m_pszFilename = CPLStrdup( pszFilename );
162 17 : }
163 :
164 : #ifdef HAVE_EXPAT
165 :
166 702 : static void XMLCALL startElementCbk(void *pUserData, const char *pszName,
167 : const char **ppszAttr)
168 : {
169 702 : ((GMLHandler*)pUserData)->startElement(pszName, ppszAttr);
170 702 : }
171 :
172 702 : static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
173 : {
174 702 : ((GMLHandler*)pUserData)->endElement(pszName);
175 702 : }
176 :
177 1801 : static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
178 : {
179 1801 : ((GMLHandler*)pUserData)->dataHandler(data, nLen);
180 1801 : }
181 :
182 : #endif
183 :
184 : /************************************************************************/
185 : /* SetupParser() */
186 : /************************************************************************/
187 :
188 23 : int GMLReader::SetupParser()
189 :
190 : {
191 : #if HAVE_XERCES == 1
192 :
193 : if( !m_bXercesInitialized )
194 : {
195 : try
196 : {
197 : XMLPlatformUtils::Initialize();
198 : }
199 :
200 : catch (const XMLException& toCatch)
201 : {
202 : CPLError( CE_Warning, CPLE_AppDefined,
203 : "Exception initializing Xerces based GML reader.\n%s",
204 : tr_strdup(toCatch.getMessage()) );
205 : return FALSE;
206 : }
207 : m_bXercesInitialized = TRUE;
208 : }
209 :
210 : // Cleanup any old parser.
211 : if( m_poSAXReader != NULL )
212 : CleanupParser();
213 :
214 : // Create and initialize parser.
215 : XMLCh* xmlUriValid = NULL;
216 : XMLCh* xmlUriNS = NULL;
217 :
218 : try{
219 : m_poSAXReader = XMLReaderFactory::createXMLReader();
220 :
221 : m_poGMLHandler = new GMLXercesHandler( this );
222 :
223 : m_poSAXReader->setContentHandler( m_poGMLHandler );
224 : m_poSAXReader->setErrorHandler( m_poGMLHandler );
225 : m_poSAXReader->setLexicalHandler( m_poGMLHandler );
226 : m_poSAXReader->setEntityResolver( m_poGMLHandler );
227 : m_poSAXReader->setDTDHandler( m_poGMLHandler );
228 :
229 : xmlUriValid = XMLString::transcode("http://xml.org/sax/features/validation");
230 : xmlUriNS = XMLString::transcode("http://xml.org/sax/features/namespaces");
231 :
232 : #if (OGR_GML_VALIDATION)
233 : m_poSAXReader->setFeature( xmlUriValid, true);
234 : m_poSAXReader->setFeature( xmlUriNS, true);
235 :
236 : m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, true );
237 : m_poSAXReader->setFeature( XMLUni::fgXercesSchema, true );
238 :
239 : // m_poSAXReader->setDoSchema(true);
240 : // m_poSAXReader->setValidationSchemaFullChecking(true);
241 : #else
242 : m_poSAXReader->setFeature( XMLUni::fgSAX2CoreValidation, false);
243 :
244 : #if XERCES_VERSION_MAJOR >= 3
245 : m_poSAXReader->setFeature( XMLUni::fgXercesSchema, false);
246 : #else
247 : m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, false);
248 : #endif
249 :
250 : #endif
251 : XMLString::release( &xmlUriValid );
252 : XMLString::release( &xmlUriNS );
253 : }
254 : catch (...)
255 : {
256 : XMLString::release( &xmlUriValid );
257 : XMLString::release( &xmlUriNS );
258 :
259 : CPLError( CE_Warning, CPLE_AppDefined,
260 : "Exception initializing Xerces based GML reader.\n" );
261 : return FALSE;
262 : }
263 : #else
264 : // Cleanup any old parser.
265 23 : if( oParser != NULL )
266 0 : CleanupParser();
267 :
268 23 : oParser = OGRCreateExpatXMLParser();
269 23 : m_poGMLHandler = new GMLExpatHandler( this, oParser );
270 :
271 23 : XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk);
272 23 : XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
273 23 : XML_SetUserData(oParser, m_poGMLHandler);
274 :
275 23 : if (fpGML != NULL)
276 7 : VSIFSeekL( fpGML, 0, SEEK_SET );
277 : #endif
278 :
279 23 : m_bReadStarted = FALSE;
280 :
281 : // Push an empty state.
282 23 : PushState( new GMLReadState() );
283 :
284 23 : return TRUE;
285 : }
286 :
287 : /************************************************************************/
288 : /* CleanupParser() */
289 : /************************************************************************/
290 :
291 43 : void GMLReader::CleanupParser()
292 :
293 : {
294 : #if HAVE_XERCES == 1
295 : if( m_poSAXReader == NULL )
296 : return;
297 : #else
298 43 : if (oParser == NULL )
299 20 : return;
300 : #endif
301 :
302 69 : while( m_poState )
303 23 : PopState();
304 :
305 : #if HAVE_XERCES == 1
306 : delete m_poSAXReader;
307 : m_poSAXReader = NULL;
308 : #else
309 23 : if (oParser)
310 23 : XML_ParserFree(oParser);
311 23 : oParser = NULL;
312 :
313 : int i;
314 24 : for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
315 1 : delete ppoFeatureTab[i];
316 23 : CPLFree(ppoFeatureTab);
317 23 : nFeatureTabIndex = 0;
318 23 : nFeatureTabLength = 0;
319 23 : ppoFeatureTab = NULL;
320 :
321 : #endif
322 :
323 23 : delete m_poGMLHandler;
324 23 : m_poGMLHandler = NULL;
325 :
326 23 : m_bReadStarted = FALSE;
327 : }
328 :
329 : /************************************************************************/
330 : /* NextFeature() */
331 : /************************************************************************/
332 :
333 : #if HAVE_XERCES == 1
334 : GMLFeature *GMLReader::NextFeature()
335 :
336 : {
337 : GMLFeature *poReturn = NULL;
338 :
339 : try
340 : {
341 : if( !m_bReadStarted )
342 : {
343 : if( m_poSAXReader == NULL )
344 : SetupParser();
345 :
346 : if( !m_poSAXReader->parseFirst( m_pszFilename, m_oToFill ) )
347 : return NULL;
348 : m_bReadStarted = TRUE;
349 : }
350 :
351 : while( m_poCompleteFeature == NULL
352 : && !m_bStopParsing
353 : && m_poSAXReader->parseNext( m_oToFill ) ) {}
354 :
355 : poReturn = m_poCompleteFeature;
356 : m_poCompleteFeature = NULL;
357 :
358 : }
359 : catch (const XMLException& toCatch)
360 : {
361 : char *pszErrorMessage = tr_strdup( toCatch.getMessage() );
362 : CPLDebug( "GML",
363 : "Error during NextFeature()! Message:\n%s",
364 : pszErrorMessage );
365 : CPLFree(pszErrorMessage);
366 : m_bStopParsing = TRUE;
367 : }
368 : catch (const SAXException& toCatch)
369 : {
370 : char *pszErrorMessage = tr_strdup( toCatch.getMessage() );
371 : CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrorMessage);
372 : CPLFree(pszErrorMessage);
373 : m_bStopParsing = TRUE;
374 : }
375 :
376 : return poReturn;
377 : }
378 : #else
379 74 : GMLFeature *GMLReader::NextFeature()
380 :
381 : {
382 74 : if (!m_bReadStarted)
383 : {
384 23 : if (oParser == NULL)
385 13 : SetupParser();
386 :
387 23 : if (fpGML == NULL)
388 16 : fpGML = VSIFOpenL(m_pszFilename, "rt");
389 :
390 23 : m_bReadStarted = TRUE;
391 : }
392 :
393 74 : if (fpGML == NULL || m_bStopParsing)
394 0 : return NULL;
395 :
396 74 : if (nFeatureTabIndex < nFeatureTabLength)
397 : {
398 35 : return ppoFeatureTab[nFeatureTabIndex++];
399 : }
400 :
401 39 : if (VSIFEofL(fpGML))
402 16 : return NULL;
403 :
404 : char aBuf[BUFSIZ];
405 :
406 23 : CPLFree(ppoFeatureTab);
407 23 : ppoFeatureTab = NULL;
408 23 : nFeatureTabLength = 0;
409 23 : nFeatureTabIndex = 0;
410 :
411 : int nDone;
412 23 : do
413 : {
414 23 : m_poGMLHandler->ResetDataHandlerCounter();
415 :
416 : unsigned int nLen =
417 23 : (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpGML );
418 23 : nDone = VSIFEofL(fpGML);
419 23 : if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
420 : {
421 : CPLError(CE_Failure, CPLE_AppDefined,
422 : "XML parsing of GML file failed : %s "
423 : "at line %d, column %d",
424 : XML_ErrorString(XML_GetErrorCode(oParser)),
425 : (int)XML_GetCurrentLineNumber(oParser),
426 0 : (int)XML_GetCurrentColumnNumber(oParser));
427 0 : m_bStopParsing = TRUE;
428 : }
429 23 : if (!m_bStopParsing)
430 23 : m_bStopParsing = m_poGMLHandler->HasStoppedParsing();
431 :
432 : } while (!nDone && !m_bStopParsing && nFeatureTabLength == 0);
433 :
434 23 : return (nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++] : NULL;
435 : }
436 : #endif
437 :
438 : /************************************************************************/
439 : /* PushFeature() */
440 : /* */
441 : /* Create a feature based on the named element. If the */
442 : /* corresponding feature class doesn't exist yet, then create */
443 : /* it now. A new GMLReadState will be created for the feature, */
444 : /* and it will be placed within that state. The state is */
445 : /* pushed onto the readstate stack. */
446 : /************************************************************************/
447 :
448 56 : void GMLReader::PushFeature( const char *pszElement,
449 : const char *pszFID )
450 :
451 : {
452 : int iClass;
453 :
454 : /* -------------------------------------------------------------------- */
455 : /* Find the class of this element. */
456 : /* -------------------------------------------------------------------- */
457 58 : for( iClass = 0; iClass < GetClassCount(); iClass++ )
458 : {
459 50 : if( EQUAL(pszElement,GetClass(iClass)->GetElementName()) )
460 48 : break;
461 : }
462 :
463 : /* -------------------------------------------------------------------- */
464 : /* Create a new feature class for this element, if there is no */
465 : /* existing class for it. */
466 : /* -------------------------------------------------------------------- */
467 56 : if( iClass == GetClassCount() )
468 : {
469 : CPLAssert( !IsClassListLocked() );
470 :
471 8 : GMLFeatureClass *poNewClass = new GMLFeatureClass( pszElement );
472 :
473 8 : AddClass( poNewClass );
474 : }
475 :
476 : /* -------------------------------------------------------------------- */
477 : /* Create a feature of this feature class. Try to set the fid */
478 : /* if available. */
479 : /* -------------------------------------------------------------------- */
480 56 : GMLFeature *poFeature = new GMLFeature( GetClass( iClass ) );
481 56 : if( pszFID != NULL )
482 : {
483 52 : poFeature->SetFID( pszFID );
484 : }
485 :
486 : /* -------------------------------------------------------------------- */
487 : /* Create and push a new read state. */
488 : /* -------------------------------------------------------------------- */
489 : GMLReadState *poState;
490 :
491 56 : poState = new GMLReadState();
492 56 : poState->m_poFeature = poFeature;
493 56 : PushState( poState );
494 56 : }
495 :
496 : /************************************************************************/
497 : /* IsFeatureElement() */
498 : /* */
499 : /* Based on context and the element name, is this element a new */
500 : /* GML feature element? */
501 : /************************************************************************/
502 :
503 566 : int GMLReader::IsFeatureElement( const char *pszElement )
504 :
505 : {
506 : CPLAssert( m_poState != NULL );
507 :
508 566 : const char *pszLast = m_poState->GetLastComponent();
509 566 : int nLen = strlen(pszLast);
510 :
511 566 : if( nLen < 6 || !(EQUAL(pszLast+nLen-6,"member") ||
512 : EQUAL(pszLast+nLen-7,"members")) )
513 510 : return FALSE;
514 :
515 : // If the class list isn't locked, any element that is a featureMember
516 : // will do.
517 56 : if( !IsClassListLocked() )
518 44 : return TRUE;
519 :
520 : // otherwise, find a class with the desired element name.
521 12 : for( int i = 0; i < GetClassCount(); i++ )
522 : {
523 12 : if( EQUAL(pszElement,GetClass(i)->GetElementName()) )
524 12 : return TRUE;
525 : }
526 :
527 0 : return FALSE;
528 : }
529 :
530 : /************************************************************************/
531 : /* IsAttributeElement() */
532 : /************************************************************************/
533 :
534 510 : int GMLReader::IsAttributeElement( const char *pszElement )
535 :
536 : {
537 510 : if( m_poState->m_poFeature == NULL )
538 260 : return FALSE;
539 :
540 250 : if( m_poState->m_nPathLength > 0 )
541 14 : return FALSE;
542 :
543 236 : GMLFeatureClass *poClass = m_poState->m_poFeature->GetClass();
544 :
545 236 : if( !poClass->IsSchemaLocked() )
546 170 : return TRUE;
547 :
548 275 : for( int i = 0; i < poClass->GetPropertyCount(); i++ )
549 262 : if( EQUAL(poClass->GetProperty(i)->GetSrcElement(),pszElement) )
550 53 : return TRUE;
551 :
552 13 : return FALSE;
553 : }
554 :
555 : /************************************************************************/
556 : /* PopState() */
557 : /************************************************************************/
558 :
559 79 : void GMLReader::PopState()
560 :
561 : {
562 79 : if( m_poState != NULL )
563 : {
564 : #if HAVE_XERCES == 1
565 : if( m_poState->m_poFeature != NULL && m_poCompleteFeature == NULL )
566 : {
567 : m_poCompleteFeature = m_poState->m_poFeature;
568 : m_poState->m_poFeature = NULL;
569 : }
570 : #else
571 79 : if ( m_poState->m_poFeature != NULL )
572 : {
573 : ppoFeatureTab = (GMLFeature**)
574 : CPLRealloc(ppoFeatureTab,
575 56 : sizeof(GMLFeature*) * (nFeatureTabLength + 1));
576 56 : ppoFeatureTab[nFeatureTabLength] = m_poState->m_poFeature;
577 56 : nFeatureTabLength++;
578 :
579 56 : m_poState->m_poFeature = NULL;
580 : }
581 : #endif
582 :
583 : GMLReadState *poParent;
584 :
585 79 : poParent = m_poState->m_poParentState;
586 :
587 79 : delete m_poState;
588 79 : m_poState = poParent;
589 : }
590 79 : }
591 :
592 : /************************************************************************/
593 : /* PushState() */
594 : /************************************************************************/
595 :
596 79 : void GMLReader::PushState( GMLReadState *poState )
597 :
598 : {
599 79 : poState->m_poParentState = m_poState;
600 79 : m_poState = poState;
601 79 : }
602 :
603 : /************************************************************************/
604 : /* GetClass() */
605 : /************************************************************************/
606 :
607 172 : GMLFeatureClass *GMLReader::GetClass( int iClass ) const
608 :
609 : {
610 172 : if( iClass < 0 || iClass >= m_nClassCount )
611 0 : return NULL;
612 : else
613 172 : return m_papoClass[iClass];
614 : }
615 :
616 : /************************************************************************/
617 : /* GetClass() */
618 : /************************************************************************/
619 :
620 15 : GMLFeatureClass *GMLReader::GetClass( const char *pszName ) const
621 :
622 : {
623 16 : for( int iClass = 0; iClass < m_nClassCount; iClass++ )
624 : {
625 16 : if( EQUAL(GetClass(iClass)->GetName(),pszName) )
626 15 : return GetClass(iClass);
627 : }
628 :
629 0 : return NULL;
630 : }
631 :
632 : /************************************************************************/
633 : /* AddClass() */
634 : /************************************************************************/
635 :
636 15 : int GMLReader::AddClass( GMLFeatureClass *poNewClass )
637 :
638 : {
639 : CPLAssert( GetClass( poNewClass->GetName() ) == NULL );
640 :
641 15 : m_nClassCount++;
642 : m_papoClass = (GMLFeatureClass **)
643 15 : CPLRealloc( m_papoClass, sizeof(void*) * m_nClassCount );
644 15 : m_papoClass[m_nClassCount-1] = poNewClass;
645 :
646 15 : return m_nClassCount-1;
647 : }
648 :
649 : /************************************************************************/
650 : /* ClearClasses() */
651 : /************************************************************************/
652 :
653 27 : void GMLReader::ClearClasses()
654 :
655 : {
656 42 : for( int i = 0; i < m_nClassCount; i++ )
657 15 : delete m_papoClass[i];
658 27 : CPLFree( m_papoClass );
659 :
660 27 : m_nClassCount = 0;
661 27 : m_papoClass = NULL;
662 27 : }
663 :
664 : /************************************************************************/
665 : /* SetFeatureProperty() */
666 : /* */
667 : /* Set the property value on the current feature, adding the */
668 : /* property name to the GMLFeatureClass if required. */
669 : /* Eventually this function may also "refine" the property */
670 : /* type based on what is encountered. */
671 : /************************************************************************/
672 :
673 179 : void GMLReader::SetFeatureProperty( const char *pszElement,
674 : const char *pszValue )
675 :
676 : {
677 179 : GMLFeature *poFeature = GetState()->m_poFeature;
678 :
679 : CPLAssert( poFeature != NULL );
680 :
681 : /* -------------------------------------------------------------------- */
682 : /* Does this property exist in the feature class? If not, add */
683 : /* it. */
684 : /* -------------------------------------------------------------------- */
685 179 : GMLFeatureClass *poClass = poFeature->GetClass();
686 : int iProperty;
687 :
688 434 : for( iProperty=0; iProperty < poClass->GetPropertyCount(); iProperty++ )
689 : {
690 413 : if( EQUAL(poClass->GetProperty( iProperty )->GetSrcElement(),
691 : pszElement ) )
692 158 : break;
693 : }
694 :
695 179 : if( iProperty == poClass->GetPropertyCount() )
696 : {
697 21 : if( poClass->IsSchemaLocked() )
698 : {
699 0 : CPLDebug("GML","Encountered property missing from class schema.");
700 0 : return;
701 : }
702 :
703 21 : GMLPropertyDefn *poPDefn = new GMLPropertyDefn(pszElement,pszElement);
704 :
705 21 : if( EQUAL(CPLGetConfigOption( "GML_FIELDTYPES", ""), "ALWAYS_STRING") )
706 0 : poPDefn->SetType( GMLPT_String );
707 :
708 21 : poClass->AddProperty( poPDefn );
709 :
710 : }
711 :
712 : /* -------------------------------------------------------------------- */
713 : /* Set the property */
714 : /* -------------------------------------------------------------------- */
715 179 : poFeature->SetProperty( iProperty, pszValue );
716 :
717 : /* -------------------------------------------------------------------- */
718 : /* Do we need to update the property type? */
719 : /* -------------------------------------------------------------------- */
720 179 : if( !poClass->IsSchemaLocked() )
721 126 : poClass->GetProperty( iProperty )->AnalysePropertyValue(pszValue);
722 : }
723 :
724 : /************************************************************************/
725 : /* LoadClasses() */
726 : /************************************************************************/
727 :
728 4 : int GMLReader::LoadClasses( const char *pszFile )
729 :
730 : {
731 : // Add logic later to determine reasonable default schema file.
732 4 : if( pszFile == NULL )
733 0 : return FALSE;
734 :
735 : /* -------------------------------------------------------------------- */
736 : /* Load the raw XML file. */
737 : /* -------------------------------------------------------------------- */
738 : FILE *fp;
739 : int nLength;
740 : char *pszWholeText;
741 :
742 4 : fp = VSIFOpen( pszFile, "rb" );
743 :
744 4 : if( fp == NULL )
745 : {
746 : CPLError( CE_Failure, CPLE_OpenFailed,
747 0 : "Failed to open file %s.", pszFile );
748 0 : return FALSE;
749 : }
750 :
751 4 : VSIFSeek( fp, 0, SEEK_END );
752 4 : nLength = VSIFTell( fp );
753 4 : VSIFSeek( fp, 0, SEEK_SET );
754 :
755 4 : pszWholeText = (char *) VSIMalloc(nLength+1);
756 4 : if( pszWholeText == NULL )
757 : {
758 : CPLError( CE_Failure, CPLE_AppDefined,
759 : "Failed to allocate %d byte buffer for %s,\n"
760 : "is this really a GMLFeatureClassList file?",
761 0 : nLength, pszFile );
762 0 : VSIFClose( fp );
763 0 : return FALSE;
764 : }
765 :
766 4 : if( VSIFRead( pszWholeText, nLength, 1, fp ) != 1 )
767 : {
768 0 : VSIFree( pszWholeText );
769 0 : VSIFClose( fp );
770 : CPLError( CE_Failure, CPLE_AppDefined,
771 0 : "Read failed on %s.", pszFile );
772 0 : return FALSE;
773 : }
774 4 : pszWholeText[nLength] = '\0';
775 :
776 4 : VSIFClose( fp );
777 :
778 4 : if( strstr( pszWholeText, "<GMLFeatureClassList>" ) == NULL )
779 : {
780 0 : VSIFree( pszWholeText );
781 : CPLError( CE_Failure, CPLE_AppDefined,
782 : "File %s does not contain a GMLFeatureClassList tree.",
783 0 : pszFile );
784 0 : return FALSE;
785 : }
786 :
787 : /* -------------------------------------------------------------------- */
788 : /* Convert to XML parse tree. */
789 : /* -------------------------------------------------------------------- */
790 : CPLXMLNode *psRoot;
791 :
792 4 : psRoot = CPLParseXMLString( pszWholeText );
793 4 : VSIFree( pszWholeText );
794 :
795 : // We assume parser will report errors via CPL.
796 4 : if( psRoot == NULL )
797 0 : return FALSE;
798 :
799 4 : if( psRoot->eType != CXT_Element
800 : || !EQUAL(psRoot->pszValue,"GMLFeatureClassList") )
801 : {
802 0 : CPLDestroyXMLNode(psRoot);
803 : CPLError( CE_Failure, CPLE_AppDefined,
804 : "File %s is not a GMLFeatureClassList document.",
805 0 : pszFile );
806 0 : return FALSE;
807 : }
808 :
809 : /* -------------------------------------------------------------------- */
810 : /* Extract feature classes for all definitions found. */
811 : /* -------------------------------------------------------------------- */
812 : CPLXMLNode *psThis;
813 :
814 8 : for( psThis = psRoot->psChild; psThis != NULL; psThis = psThis->psNext )
815 : {
816 4 : if( psThis->eType == CXT_Element
817 : && EQUAL(psThis->pszValue,"GMLFeatureClass") )
818 : {
819 : GMLFeatureClass *poClass;
820 :
821 4 : poClass = new GMLFeatureClass();
822 :
823 4 : if( !poClass->InitializeFromXML( psThis ) )
824 : {
825 0 : delete poClass;
826 0 : CPLDestroyXMLNode( psRoot );
827 0 : return FALSE;
828 : }
829 :
830 4 : poClass->SetSchemaLocked( TRUE );
831 :
832 4 : AddClass( poClass );
833 : }
834 : }
835 :
836 4 : CPLDestroyXMLNode( psRoot );
837 :
838 4 : SetClassListLocked( TRUE );
839 :
840 4 : return TRUE;
841 : }
842 :
843 : /************************************************************************/
844 : /* SaveClasses() */
845 : /************************************************************************/
846 :
847 7 : int GMLReader::SaveClasses( const char *pszFile )
848 :
849 : {
850 : // Add logic later to determine reasonable default schema file.
851 7 : if( pszFile == NULL )
852 0 : return FALSE;
853 :
854 : /* -------------------------------------------------------------------- */
855 : /* Create in memory schema tree. */
856 : /* -------------------------------------------------------------------- */
857 : CPLXMLNode *psRoot;
858 :
859 7 : psRoot = CPLCreateXMLNode( NULL, CXT_Element, "GMLFeatureClassList" );
860 :
861 15 : for( int iClass = 0; iClass < GetClassCount(); iClass++ )
862 : {
863 8 : GMLFeatureClass *poClass = GetClass( iClass );
864 :
865 8 : CPLAddXMLChild( psRoot, poClass->SerializeToXML() );
866 : }
867 :
868 : /* -------------------------------------------------------------------- */
869 : /* Serialize to disk. */
870 : /* -------------------------------------------------------------------- */
871 : FILE *fp;
872 7 : int bSuccess = TRUE;
873 7 : char *pszWholeText = CPLSerializeXMLTree( psRoot );
874 :
875 7 : CPLDestroyXMLNode( psRoot );
876 :
877 7 : fp = VSIFOpen( pszFile, "wb" );
878 :
879 7 : if( fp == NULL )
880 0 : bSuccess = FALSE;
881 7 : else if( VSIFWrite( pszWholeText, strlen(pszWholeText), 1, fp ) != 1 )
882 0 : bSuccess = FALSE;
883 : else
884 7 : VSIFClose( fp );
885 :
886 7 : CPLFree( pszWholeText );
887 :
888 7 : return bSuccess;
889 : }
890 :
891 : /************************************************************************/
892 : /* PrescanForSchema() */
893 : /* */
894 : /* For now we use a pretty dumb approach of just doing a normal */
895 : /* scan of the whole file, building up the schema information. */
896 : /* Eventually we hope to do a more efficient scan when just */
897 : /* looking for schema information. */
898 : /************************************************************************/
899 :
900 10 : int GMLReader::PrescanForSchema( int bGetExtents )
901 :
902 : {
903 : GMLFeature *poFeature;
904 :
905 10 : if( m_pszFilename == NULL )
906 0 : return FALSE;
907 :
908 10 : SetClassListLocked( FALSE );
909 :
910 10 : ClearClasses();
911 10 : if( !SetupParser() )
912 0 : return FALSE;
913 :
914 42 : while( (poFeature = NextFeature()) != NULL )
915 : {
916 22 : GMLFeatureClass *poClass = poFeature->GetClass();
917 :
918 22 : if( poClass->GetFeatureCount() == -1 )
919 8 : poClass->SetFeatureCount( 1 );
920 : else
921 14 : poClass->SetFeatureCount( poClass->GetFeatureCount() + 1 );
922 :
923 : #ifdef SUPPORT_GEOMETRY
924 22 : if( bGetExtents )
925 : {
926 22 : OGRGeometry *poGeometry = NULL;
927 :
928 22 : if( poFeature->GetGeometry() != NULL
929 : && strlen(poFeature->GetGeometry()) != 0 )
930 : {
931 : poGeometry = OGRGeometryFactory::createFromGML(
932 22 : poFeature->GetGeometry() );
933 : }
934 :
935 22 : if( poGeometry != NULL )
936 : {
937 : double dfXMin, dfXMax, dfYMin, dfYMax;
938 22 : OGREnvelope sEnvelope;
939 :
940 22 : poGeometry->getEnvelope( &sEnvelope );
941 22 : delete poGeometry;
942 22 : if( poClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax) )
943 : {
944 14 : dfXMin = MIN(dfXMin,sEnvelope.MinX);
945 14 : dfXMax = MAX(dfXMax,sEnvelope.MaxX);
946 14 : dfYMin = MIN(dfYMin,sEnvelope.MinY);
947 14 : dfYMax = MAX(dfYMax,sEnvelope.MaxY);
948 : }
949 : else
950 : {
951 8 : dfXMin = sEnvelope.MinX;
952 8 : dfXMax = sEnvelope.MaxX;
953 8 : dfYMin = sEnvelope.MinY;
954 8 : dfYMax = sEnvelope.MaxY;
955 : }
956 :
957 22 : poClass->SetExtents( dfXMin, dfXMax, dfYMin, dfYMax );
958 : }
959 : #endif /* def SUPPORT_GEOMETRY */
960 : }
961 :
962 22 : delete poFeature;
963 : }
964 :
965 10 : CleanupParser();
966 :
967 10 : return GetClassCount() > 0;
968 : }
969 :
970 : /************************************************************************/
971 : /* ResetReading() */
972 : /************************************************************************/
973 :
974 16 : void GMLReader::ResetReading()
975 :
976 : {
977 16 : CleanupParser();
978 16 : }
979 :
980 : #endif /* HAVE_XERCES == 1 or HAVE_EXPAT */
981 :
|