1 : /******************************************************************************
2 : * $Id: nasreader.cpp 25656 2013-02-19 15:40:20Z ilucena $
3 : *
4 : * Project: NAS Reader
5 : * Purpose: Implementation of NASReader 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 : #include "cpl_string.h"
33 : #include "gmlutils.h"
34 :
35 : #define SUPPORT_GEOMETRY
36 :
37 : #ifdef SUPPORT_GEOMETRY
38 : # include "ogr_geometry.h"
39 : #endif
40 :
41 : /************************************************************************/
42 : /* ==================================================================== */
43 : /* With XERCES Library */
44 : /* ==================================================================== */
45 : /************************************************************************/
46 :
47 : #include "nasreaderp.h"
48 : #include "cpl_conv.h"
49 :
50 : /************************************************************************/
51 : /* CreateGMLReader() */
52 : /************************************************************************/
53 :
54 5 : IGMLReader *CreateNASReader()
55 :
56 : {
57 5 : return new NASReader();
58 : }
59 :
60 : /************************************************************************/
61 : /* GMLReader() */
62 : /************************************************************************/
63 :
64 5 : NASReader::NASReader()
65 :
66 : {
67 5 : m_nClassCount = 0;
68 5 : m_papoClass = NULL;
69 :
70 5 : m_bClassListLocked = FALSE;
71 :
72 5 : m_poNASHandler = NULL;
73 5 : m_poSAXReader = NULL;
74 5 : m_bReadStarted = FALSE;
75 :
76 5 : m_poState = NULL;
77 5 : m_poCompleteFeature = NULL;
78 :
79 5 : m_pszFilename = NULL;
80 5 : m_pszFilteredClassName = NULL;
81 5 : }
82 :
83 : /************************************************************************/
84 : /* ~NASReader() */
85 : /************************************************************************/
86 :
87 5 : NASReader::~NASReader()
88 :
89 : {
90 5 : ClearClasses();
91 :
92 5 : CPLFree( m_pszFilename );
93 :
94 5 : CleanupParser();
95 :
96 5 : if (CSLTestBoolean(CPLGetConfigOption("NAS_XERCES_TERMINATE", "FALSE")))
97 0 : XMLPlatformUtils::Terminate();
98 :
99 5 : CPLFree( m_pszFilteredClassName );
100 5 : }
101 :
102 : /************************************************************************/
103 : /* SetSourceFile() */
104 : /************************************************************************/
105 :
106 5 : void NASReader::SetSourceFile( const char *pszFilename )
107 :
108 : {
109 5 : CPLFree( m_pszFilename );
110 5 : m_pszFilename = CPLStrdup( pszFilename );
111 5 : }
112 :
113 : /************************************************************************/
114 : /* GetSourceFileName() */
115 : /************************************************************************/
116 :
117 0 : const char* NASReader::GetSourceFileName()
118 :
119 : {
120 0 : return m_pszFilename;
121 : }
122 :
123 : /************************************************************************/
124 : /* SetupParser() */
125 : /************************************************************************/
126 :
127 9 : int NASReader::SetupParser()
128 :
129 : {
130 : static int bXercesInitialized = FALSE;
131 :
132 9 : if( !bXercesInitialized )
133 : {
134 : try
135 : {
136 1 : XMLPlatformUtils::Initialize();
137 : }
138 :
139 0 : catch (const XMLException& toCatch)
140 : {
141 : CPLError( CE_Warning, CPLE_AppDefined,
142 : "Exception initializing Xerces based GML reader.\n%s",
143 0 : tr_strdup(toCatch.getMessage()) );
144 0 : return FALSE;
145 : }
146 1 : bXercesInitialized = TRUE;
147 : }
148 :
149 : // Cleanup any old parser.
150 9 : if( m_poSAXReader != NULL )
151 0 : CleanupParser();
152 :
153 : // Create and initialize parser.
154 9 : XMLCh* xmlUriValid = NULL;
155 9 : XMLCh* xmlUriNS = NULL;
156 :
157 : try{
158 9 : m_poSAXReader = XMLReaderFactory::createXMLReader();
159 :
160 9 : m_poNASHandler = new NASHandler( this );
161 :
162 18 : m_poSAXReader->setContentHandler( m_poNASHandler );
163 9 : m_poSAXReader->setErrorHandler( m_poNASHandler );
164 9 : m_poSAXReader->setLexicalHandler( m_poNASHandler );
165 9 : m_poSAXReader->setEntityResolver( m_poNASHandler );
166 9 : m_poSAXReader->setDTDHandler( m_poNASHandler );
167 :
168 9 : xmlUriValid = XMLString::transcode("http://xml.org/sax/features/validation");
169 9 : xmlUriNS = XMLString::transcode("http://xml.org/sax/features/namespaces");
170 :
171 : #if (OGR_GML_VALIDATION)
172 : m_poSAXReader->setFeature( xmlUriValid, true);
173 : m_poSAXReader->setFeature( xmlUriNS, true);
174 :
175 : m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, true );
176 : m_poSAXReader->setFeature( XMLUni::fgXercesSchema, true );
177 :
178 : // m_poSAXReader->setDoSchema(true);
179 : // m_poSAXReader->setValidationSchemaFullChecking(true);
180 : #else
181 9 : m_poSAXReader->setFeature( XMLUni::fgSAX2CoreValidation, false);
182 :
183 : #if XERCES_VERSION_MAJOR >= 3
184 : m_poSAXReader->setFeature( XMLUni::fgXercesSchema, false);
185 : #else
186 9 : m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, false);
187 : #endif
188 :
189 : #endif
190 9 : XMLString::release( &xmlUriValid );
191 9 : XMLString::release( &xmlUriNS );
192 : }
193 0 : catch (...)
194 : {
195 0 : XMLString::release( &xmlUriValid );
196 0 : XMLString::release( &xmlUriNS );
197 :
198 : CPLError( CE_Warning, CPLE_AppDefined,
199 0 : "Exception initializing Xerces based GML reader.\n" );
200 0 : return FALSE;
201 : }
202 :
203 9 : m_bReadStarted = FALSE;
204 :
205 : // Push an empty state.
206 18 : PushState( new GMLReadState() );
207 :
208 9 : return TRUE;
209 : }
210 :
211 : /************************************************************************/
212 : /* CleanupParser() */
213 : /************************************************************************/
214 :
215 17 : void NASReader::CleanupParser()
216 :
217 : {
218 17 : if( m_poSAXReader == NULL )
219 8 : return;
220 :
221 27 : while( m_poState )
222 9 : PopState();
223 :
224 9 : delete m_poSAXReader;
225 9 : m_poSAXReader = NULL;
226 :
227 9 : delete m_poNASHandler;
228 9 : m_poNASHandler = NULL;
229 :
230 9 : delete m_poCompleteFeature;
231 9 : m_poCompleteFeature = NULL;
232 :
233 9 : m_bReadStarted = FALSE;
234 : }
235 :
236 : /************************************************************************/
237 : /* NextFeature() */
238 : /************************************************************************/
239 :
240 8738 : GMLFeature *NASReader::NextFeature()
241 :
242 : {
243 8738 : GMLFeature *poReturn = NULL;
244 :
245 : try
246 : {
247 8738 : if( !m_bReadStarted )
248 : {
249 9 : if( m_poSAXReader == NULL )
250 6 : SetupParser();
251 :
252 9 : if( !m_poSAXReader->parseFirst( m_pszFilename, m_oToFill ) )
253 0 : return NULL;
254 9 : m_bReadStarted = TRUE;
255 : }
256 :
257 17661102 : while( m_poCompleteFeature == NULL
258 8826184 : && m_poSAXReader->parseNext( m_oToFill ) ) {}
259 :
260 8738 : poReturn = m_poCompleteFeature;
261 8738 : m_poCompleteFeature = NULL;
262 :
263 : }
264 0 : catch (const XMLException& toCatch)
265 : {
266 : CPLDebug( "NAS",
267 : "Error during NextFeature()! Message:\n%s",
268 0 : tr_strdup( toCatch.getMessage() ) );
269 : }
270 :
271 8738 : return poReturn;
272 : }
273 :
274 : /************************************************************************/
275 : /* PushFeature() */
276 : /* */
277 : /* Create a feature based on the named element. If the */
278 : /* corresponding feature class doesn't exist yet, then create */
279 : /* it now. A new GMLReadState will be created for the feature, */
280 : /* and it will be placed within that state. The state is */
281 : /* pushed onto the readstate stack. */
282 : /************************************************************************/
283 :
284 8734 : void NASReader::PushFeature( const char *pszElement,
285 : const Attributes &attrs )
286 :
287 : {
288 : int iClass;
289 :
290 : /* -------------------------------------------------------------------- */
291 : /* Find the class of this element. */
292 : /* -------------------------------------------------------------------- */
293 150035 : for( iClass = 0; iClass < GetClassCount(); iClass++ )
294 : {
295 150032 : if( EQUAL(pszElement,GetClass(iClass)->GetElementName()) )
296 8731 : break;
297 : }
298 :
299 : /* -------------------------------------------------------------------- */
300 : /* Create a new feature class for this element, if there is no */
301 : /* existing class for it. */
302 : /* -------------------------------------------------------------------- */
303 8734 : if( iClass == GetClassCount() )
304 : {
305 3 : CPLAssert( !IsClassListLocked() );
306 :
307 3 : GMLFeatureClass *poNewClass = new GMLFeatureClass( pszElement );
308 :
309 3 : iClass = AddClass( poNewClass );
310 : }
311 :
312 : /* -------------------------------------------------------------------- */
313 : /* Create a feature of this feature class. */
314 : /* -------------------------------------------------------------------- */
315 8734 : GMLFeature *poFeature = new GMLFeature( GetClass( iClass ) );
316 :
317 : /* -------------------------------------------------------------------- */
318 : /* Create and push a new read state. */
319 : /* -------------------------------------------------------------------- */
320 : GMLReadState *poState;
321 :
322 17468 : poState = new GMLReadState();
323 8734 : poState->m_poFeature = poFeature;
324 8734 : PushState( poState );
325 :
326 : /* -------------------------------------------------------------------- */
327 : /* Check for gml:id, and if found push it as an attribute named */
328 : /* gml_id. */
329 : /* -------------------------------------------------------------------- */
330 : int nFIDIndex;
331 : XMLCh anFID[100];
332 :
333 8734 : tr_strcpy( anFID, "gml:id" );
334 8734 : nFIDIndex = attrs.getIndex( anFID );
335 8734 : if( nFIDIndex != -1 )
336 : {
337 8728 : char *pszFID = tr_strdup( attrs.getValue( nFIDIndex ) );
338 8728 : SetFeaturePropertyDirectly( "gml_id", pszFID );
339 : }
340 :
341 8734 : }
342 :
343 : /************************************************************************/
344 : /* IsFeatureElement() */
345 : /* */
346 : /* Based on context and the element name, is this element a new */
347 : /* GML feature element? */
348 : /************************************************************************/
349 :
350 221593 : int NASReader::IsFeatureElement( const char *pszElement )
351 :
352 : {
353 221593 : CPLAssert( m_poState != NULL );
354 :
355 221593 : const char *pszLast = m_poState->GetLastComponent();
356 221593 : int nLen = strlen(pszLast);
357 :
358 : // There seem to be two major NAS classes of feature identifiers
359 : // -- either a wfs:Insert or a gml:featureMember.
360 :
361 221593 : if( (nLen < 6 || !EQUAL(pszLast+nLen-6,"Insert"))
362 : && (nLen < 13 || !EQUAL(pszLast+nLen-13,"featureMember"))
363 : && (nLen < 7 || !EQUAL(pszLast+nLen-7,"Replace")) )
364 151947 : return FALSE;
365 :
366 : // If the class list isn't locked, any element that is a featureMember
367 : // will do.
368 69646 : if( !IsClassListLocked() )
369 3 : return TRUE;
370 :
371 : // otherwise, find a class with the desired element name.
372 1090803 : for( int i = 0; i < GetClassCount(); i++ )
373 : {
374 1090803 : if( EQUAL(pszElement,GetClass(i)->GetElementName()) )
375 69643 : return TRUE;
376 : }
377 :
378 0 : return FALSE;
379 : }
380 :
381 : /************************************************************************/
382 : /* IsAttributeElement() */
383 : /************************************************************************/
384 :
385 151940 : int NASReader::IsAttributeElement( const char *pszElement )
386 :
387 : {
388 151940 : if( m_poState->m_poFeature == NULL )
389 69849 : return FALSE;
390 :
391 82091 : GMLFeatureClass *poClass = m_poState->m_poFeature->GetClass();
392 :
393 : // If the schema is not yet locked, then any simple element
394 : // is potentially an attribute.
395 82091 : if( !poClass->IsSchemaLocked() )
396 76 : return TRUE;
397 :
398 : // Otherwise build the path to this element into a single string
399 : // and compare against known attributes.
400 82015 : CPLString osElemPath;
401 :
402 82015 : if( m_poState->m_nPathLength == 0 )
403 41887 : osElemPath = pszElement;
404 : else
405 : {
406 40128 : osElemPath = m_poState->osPath;
407 40128 : osElemPath += "|";
408 40128 : osElemPath += pszElement;
409 : }
410 :
411 566143 : for( int i = 0; i < poClass->GetPropertyCount(); i++ )
412 521929 : if( EQUAL(poClass->GetProperty(i)->GetSrcElement(),osElemPath) )
413 37801 : return TRUE;
414 :
415 44214 : return FALSE;
416 : }
417 :
418 : /************************************************************************/
419 : /* PopState() */
420 : /************************************************************************/
421 :
422 8743 : void NASReader::PopState()
423 :
424 : {
425 8743 : if( m_poState != NULL )
426 : {
427 8743 : if( m_poState->m_poFeature != NULL && m_poCompleteFeature == NULL )
428 : {
429 8734 : m_poCompleteFeature = m_poState->m_poFeature;
430 8734 : m_poState->m_poFeature = NULL;
431 : }
432 :
433 : GMLReadState *poParent;
434 :
435 8743 : poParent = m_poState->m_poParentState;
436 :
437 8743 : delete m_poState;
438 8743 : m_poState = poParent;
439 : }
440 8743 : }
441 :
442 : /************************************************************************/
443 : /* PushState() */
444 : /************************************************************************/
445 :
446 8743 : void NASReader::PushState( GMLReadState *poState )
447 :
448 : {
449 8743 : poState->m_poParentState = m_poState;
450 8743 : m_poState = poState;
451 8743 : }
452 :
453 : /************************************************************************/
454 : /* GetClass() */
455 : /************************************************************************/
456 :
457 1258487 : GMLFeatureClass *NASReader::GetClass( int iClass ) const
458 :
459 : {
460 1258487 : if( iClass < 0 || iClass >= m_nClassCount )
461 0 : return NULL;
462 : else
463 1258487 : return m_papoClass[iClass];
464 : }
465 :
466 : /************************************************************************/
467 : /* GetClass() */
468 : /************************************************************************/
469 :
470 254 : GMLFeatureClass *NASReader::GetClass( const char *pszName ) const
471 :
472 : {
473 8788 : for( int iClass = 0; iClass < m_nClassCount; iClass++ )
474 : {
475 8661 : if( EQUAL(GetClass(iClass)->GetName(),pszName) )
476 127 : return GetClass(iClass);
477 : }
478 :
479 127 : return NULL;
480 : }
481 :
482 : /************************************************************************/
483 : /* AddClass() */
484 : /************************************************************************/
485 :
486 127 : int NASReader::AddClass( GMLFeatureClass *poNewClass )
487 :
488 : {
489 127 : CPLAssert( GetClass( poNewClass->GetName() ) == NULL );
490 :
491 127 : m_nClassCount++;
492 : m_papoClass = (GMLFeatureClass **)
493 127 : CPLRealloc( m_papoClass, sizeof(void*) * m_nClassCount );
494 :
495 : // keep delete the last entry
496 127 : if( m_nClassCount > 1 && EQUAL( m_papoClass[m_nClassCount-2]->GetName(), "Delete" ) )
497 : {
498 0 : m_papoClass[m_nClassCount-1] = m_papoClass[m_nClassCount-2];
499 0 : m_papoClass[m_nClassCount-2] = poNewClass;
500 0 : return m_nClassCount-2;
501 : }
502 : else
503 : {
504 127 : m_papoClass[m_nClassCount-1] = poNewClass;
505 127 : return m_nClassCount-1;
506 : }
507 : }
508 :
509 : /************************************************************************/
510 : /* ClearClasses() */
511 : /************************************************************************/
512 :
513 8 : void NASReader::ClearClasses()
514 :
515 : {
516 135 : for( int i = 0; i < m_nClassCount; i++ )
517 127 : delete m_papoClass[i];
518 8 : CPLFree( m_papoClass );
519 :
520 8 : m_nClassCount = 0;
521 8 : m_papoClass = NULL;
522 8 : }
523 :
524 : /************************************************************************/
525 : /* SetFeatureProperty() */
526 : /* */
527 : /* Set the property value on the current feature, adding the */
528 : /* property name to the GMLFeatureClass if required. */
529 : /* The pszValue ownership is passed to this function. */
530 : /************************************************************************/
531 :
532 46595 : void NASReader::SetFeaturePropertyDirectly( const char *pszElement,
533 : char *pszValue )
534 :
535 : {
536 46595 : GMLFeature *poFeature = GetState()->m_poFeature;
537 :
538 46595 : CPLAssert( poFeature != NULL );
539 :
540 : /* -------------------------------------------------------------------- */
541 : /* Does this property exist in the feature class? If not, add */
542 : /* it. */
543 : /* -------------------------------------------------------------------- */
544 46595 : GMLFeatureClass *poClass = poFeature->GetClass();
545 : int iProperty;
546 :
547 197341 : for( iProperty=0; iProperty < poClass->GetPropertyCount(); iProperty++ )
548 : {
549 197311 : if( EQUAL(poClass->GetProperty( iProperty )->GetSrcElement(),
550 : pszElement ) )
551 46565 : break;
552 : }
553 :
554 46595 : if( iProperty == poClass->GetPropertyCount() )
555 : {
556 30 : if( poClass->IsSchemaLocked() )
557 : {
558 0 : CPLDebug("NAS", "Encountered property missing from class schema.");
559 0 : CPLFree(pszValue);
560 0 : return;
561 : }
562 :
563 30 : CPLString osFieldName;
564 :
565 30 : if( strchr(pszElement,'|') == NULL )
566 19 : osFieldName = pszElement;
567 : else
568 : {
569 11 : osFieldName = strrchr(pszElement,'|') + 1;
570 11 : if( poClass->GetPropertyIndex(osFieldName) != -1 )
571 2 : osFieldName = pszElement;
572 : }
573 :
574 : // Does this conflict with an existing property name?
575 60 : while( poClass->GetProperty(osFieldName) != NULL )
576 : {
577 0 : osFieldName += "_";
578 : }
579 :
580 30 : GMLPropertyDefn *poPDefn = new GMLPropertyDefn(osFieldName,pszElement);
581 :
582 60 : if( EQUAL(CPLGetConfigOption( "GML_FIELDTYPES", ""), "ALWAYS_STRING") )
583 0 : poPDefn->SetType( GMLPT_String );
584 :
585 30 : poClass->AddProperty( poPDefn );
586 : }
587 :
588 46595 : if ( GMLPropertyDefn::IsSimpleType( poClass->GetProperty( iProperty )->GetType() ) )
589 : {
590 43277 : const GMLProperty *poProp = poFeature->GetProperty(iProperty);
591 43277 : if ( poProp && poProp->nSubProperties > 0 )
592 : {
593 0 : int iId = poClass->GetPropertyIndex( "gml_id" );
594 0 : const GMLProperty *poIdProp = poFeature->GetProperty(iId);
595 :
596 : CPLDebug("NAS",
597 : "Overwriting existing property %s.%s of value '%s' with '%s' (gml_id: %s).",
598 : poClass->GetName(), pszElement,
599 : poProp->papszSubProperties[0], pszValue,
600 0 : poIdProp && poIdProp->nSubProperties>0 && poIdProp->papszSubProperties[0] ? poIdProp->papszSubProperties[0] : "(null)" );
601 : }
602 : }
603 :
604 : /* -------------------------------------------------------------------- */
605 : /* We want to handle <lage> specially to ensure it is zero */
606 : /* filled, and treated as a string depspite the numeric */
607 : /* content. https://trac.wheregroup.com/PostNAS/ticket/9 */
608 : /* -------------------------------------------------------------------- */
609 46595 : if( strcmp(poClass->GetProperty(iProperty)->GetName(),"lage") == 0 )
610 : {
611 315 : if( strlen(pszValue) < 5 )
612 : {
613 0 : CPLString osValue = "00000";
614 0 : osValue += pszValue;
615 0 : poFeature->SetPropertyDirectly( iProperty, CPLStrdup(osValue + osValue.size() - 5) );
616 0 : CPLFree(pszValue);
617 : }
618 : else
619 315 : poFeature->SetPropertyDirectly( iProperty, pszValue );
620 :
621 315 : if( !poClass->IsSchemaLocked() )
622 : {
623 0 : poClass->GetProperty(iProperty)->SetWidth( 5 );
624 0 : poClass->GetProperty(iProperty)->SetType( GMLPT_String );
625 : }
626 315 : return;
627 : }
628 46280 : else if( strcmp(poClass->GetProperty(iProperty)->GetName(),"kartendarstellung") == 0 ||
629 : strcmp(poClass->GetProperty(iProperty)->GetName(),"rechtsbehelfsverfahren") == 0 )
630 : {
631 : poFeature->SetPropertyDirectly( iProperty,
632 335 : CPLStrdup( EQUAL( pszValue, "true" ) ? "1" : "0" ) );
633 335 : CPLFree(pszValue);
634 :
635 335 : if( !poClass->IsSchemaLocked() )
636 : {
637 2 : poClass->GetProperty(iProperty)->SetType( GMLPT_Integer );
638 : }
639 335 : return;
640 : }
641 :
642 : /* -------------------------------------------------------------------- */
643 : /* Set the property */
644 : /* -------------------------------------------------------------------- */
645 45945 : poFeature->SetPropertyDirectly( iProperty, pszValue );
646 :
647 : /* -------------------------------------------------------------------- */
648 : /* Do we need to update the property type? */
649 : /* -------------------------------------------------------------------- */
650 45945 : if( !poClass->IsSchemaLocked() )
651 : {
652 : // Special handling for punktkennung per NAS #12
653 66 : if( strcmp(poClass->GetProperty(iProperty)->GetName(),
654 : "punktkennung") == 0)
655 : {
656 0 : poClass->GetProperty(iProperty)->SetWidth( 15 );
657 0 : poClass->GetProperty(iProperty)->SetType( GMLPT_String );
658 : }
659 : // Special handling for artDerFlurstuecksgrenze per http://trac.osgeo.org/gdal/ticket/4255
660 66 : else if( strcmp(poClass->GetProperty(iProperty)->GetName(),
661 : "artDerFlurstuecksgrenze") == 0)
662 : {
663 0 : poClass->GetProperty(iProperty)->SetType( GMLPT_IntegerList );
664 : }
665 : else
666 : poClass->GetProperty(iProperty)->AnalysePropertyValue(
667 66 : poFeature->GetProperty(iProperty));
668 : }
669 : }
670 :
671 : /************************************************************************/
672 : /* LoadClasses() */
673 : /************************************************************************/
674 :
675 2 : int NASReader::LoadClasses( const char *pszFile )
676 :
677 : {
678 : // Add logic later to determine reasonable default schema file.
679 2 : if( pszFile == NULL )
680 0 : return FALSE;
681 :
682 : /* -------------------------------------------------------------------- */
683 : /* Load the raw XML file. */
684 : /* -------------------------------------------------------------------- */
685 : FILE *fp;
686 : int nLength;
687 : char *pszWholeText;
688 :
689 2 : fp = VSIFOpen( pszFile, "rb" );
690 :
691 2 : if( fp == NULL )
692 : {
693 : CPLError( CE_Failure, CPLE_OpenFailed,
694 0 : "Failed to open file %s.", pszFile );
695 0 : return FALSE;
696 : }
697 :
698 2 : VSIFSeek( fp, 0, SEEK_END );
699 2 : nLength = VSIFTell( fp );
700 2 : VSIFSeek( fp, 0, SEEK_SET );
701 :
702 2 : pszWholeText = (char *) VSIMalloc(nLength+1);
703 2 : if( pszWholeText == NULL )
704 : {
705 : CPLError( CE_Failure, CPLE_AppDefined,
706 : "Failed to allocate %d byte buffer for %s,\n"
707 : "is this really a GMLFeatureClassList file?",
708 0 : nLength, pszFile );
709 0 : VSIFClose( fp );
710 0 : return FALSE;
711 : }
712 :
713 2 : if( VSIFRead( pszWholeText, nLength, 1, fp ) != 1 )
714 : {
715 0 : VSIFree( pszWholeText );
716 0 : VSIFClose( fp );
717 : CPLError( CE_Failure, CPLE_AppDefined,
718 0 : "Read failed on %s.", pszFile );
719 0 : return FALSE;
720 : }
721 2 : pszWholeText[nLength] = '\0';
722 :
723 2 : VSIFClose( fp );
724 :
725 2 : if( strstr( pszWholeText, "<GMLFeatureClassList>" ) == NULL )
726 : {
727 0 : VSIFree( pszWholeText );
728 : CPLError( CE_Failure, CPLE_AppDefined,
729 : "File %s does not contain a GMLFeatureClassList tree.",
730 0 : pszFile );
731 0 : return FALSE;
732 : }
733 :
734 : /* -------------------------------------------------------------------- */
735 : /* Convert to XML parse tree. */
736 : /* -------------------------------------------------------------------- */
737 : CPLXMLNode *psRoot;
738 :
739 2 : psRoot = CPLParseXMLString( pszWholeText );
740 2 : VSIFree( pszWholeText );
741 :
742 : // We assume parser will report errors via CPL.
743 2 : if( psRoot == NULL )
744 0 : return FALSE;
745 :
746 2 : if( psRoot->eType != CXT_Element
747 : || !EQUAL(psRoot->pszValue,"GMLFeatureClassList") )
748 : {
749 0 : CPLDestroyXMLNode(psRoot);
750 : CPLError( CE_Failure, CPLE_AppDefined,
751 : "File %s is not a GMLFeatureClassList document.",
752 0 : pszFile );
753 0 : return FALSE;
754 : }
755 :
756 : /* -------------------------------------------------------------------- */
757 : /* Extract feature classes for all definitions found. */
758 : /* -------------------------------------------------------------------- */
759 : CPLXMLNode *psThis;
760 :
761 126 : for( psThis = psRoot->psChild; psThis != NULL; psThis = psThis->psNext )
762 : {
763 124 : if( psThis->eType == CXT_Element
764 : && EQUAL(psThis->pszValue,"GMLFeatureClass") )
765 : {
766 : GMLFeatureClass *poClass;
767 :
768 124 : poClass = new GMLFeatureClass();
769 :
770 124 : if( !poClass->InitializeFromXML( psThis ) )
771 : {
772 0 : delete poClass;
773 0 : CPLDestroyXMLNode( psRoot );
774 0 : return FALSE;
775 : }
776 :
777 124 : poClass->SetSchemaLocked( TRUE );
778 :
779 124 : AddClass( poClass );
780 : }
781 : }
782 :
783 2 : CPLDestroyXMLNode( psRoot );
784 :
785 2 : SetClassListLocked( TRUE );
786 :
787 2 : return TRUE;
788 : }
789 :
790 : /************************************************************************/
791 : /* SaveClasses() */
792 : /************************************************************************/
793 :
794 2 : int NASReader::SaveClasses( const char *pszFile )
795 :
796 : {
797 : // Add logic later to determine reasonable default schema file.
798 2 : if( pszFile == NULL )
799 0 : return FALSE;
800 :
801 : /* -------------------------------------------------------------------- */
802 : /* Create in memory schema tree. */
803 : /* -------------------------------------------------------------------- */
804 : CPLXMLNode *psRoot;
805 :
806 2 : psRoot = CPLCreateXMLNode( NULL, CXT_Element, "GMLFeatureClassList" );
807 :
808 5 : for( int iClass = 0; iClass < GetClassCount(); iClass++ )
809 : {
810 3 : GMLFeatureClass *poClass = GetClass( iClass );
811 :
812 3 : CPLAddXMLChild( psRoot, poClass->SerializeToXML() );
813 : }
814 :
815 : /* -------------------------------------------------------------------- */
816 : /* Serialize to disk. */
817 : /* -------------------------------------------------------------------- */
818 : FILE *fp;
819 2 : int bSuccess = TRUE;
820 2 : char *pszWholeText = CPLSerializeXMLTree( psRoot );
821 :
822 2 : CPLDestroyXMLNode( psRoot );
823 :
824 2 : fp = VSIFOpen( pszFile, "wb" );
825 :
826 2 : if( fp == NULL )
827 0 : bSuccess = FALSE;
828 2 : else if( VSIFWrite( pszWholeText, strlen(pszWholeText), 1, fp ) != 1 )
829 0 : bSuccess = FALSE;
830 : else
831 2 : VSIFClose( fp );
832 :
833 2 : CPLFree( pszWholeText );
834 :
835 2 : return bSuccess;
836 : }
837 :
838 : /************************************************************************/
839 : /* PrescanForSchema() */
840 : /* */
841 : /* For now we use a pretty dumb approach of just doing a normal */
842 : /* scan of the whole file, building up the schema information. */
843 : /* Eventually we hope to do a more efficient scan when just */
844 : /* looking for schema information. */
845 : /************************************************************************/
846 :
847 3 : int NASReader::PrescanForSchema( int bGetExtents )
848 :
849 : {
850 : GMLFeature *poFeature;
851 :
852 3 : if( m_pszFilename == NULL )
853 0 : return FALSE;
854 :
855 3 : SetClassListLocked( FALSE );
856 :
857 3 : ClearClasses();
858 3 : if( !SetupParser() )
859 0 : return FALSE;
860 :
861 3 : std::string osWork;
862 :
863 11 : while( (poFeature = NextFeature()) != NULL )
864 : {
865 5 : GMLFeatureClass *poClass = poFeature->GetClass();
866 :
867 5 : if( poClass->GetFeatureCount() == -1 )
868 3 : poClass->SetFeatureCount( 1 );
869 : else
870 2 : poClass->SetFeatureCount( poClass->GetFeatureCount() + 1 );
871 :
872 : #ifdef SUPPORT_GEOMETRY
873 5 : if( bGetExtents )
874 : {
875 5 : OGRGeometry *poGeometry = NULL;
876 :
877 5 : const CPLXMLNode* const * papsGeometry = poFeature->GetGeometryList();
878 5 : if( papsGeometry[0] != NULL )
879 : {
880 1 : poGeometry = (OGRGeometry*) OGR_G_CreateFromGMLTree(papsGeometry[0]);
881 : }
882 :
883 5 : if( poGeometry != NULL )
884 : {
885 : double dfXMin, dfXMax, dfYMin, dfYMax;
886 1 : OGREnvelope sEnvelope;
887 : OGRwkbGeometryType eGType = (OGRwkbGeometryType)
888 1 : poClass->GetGeometryType();
889 :
890 : // Merge SRSName into layer.
891 1 : const char* pszSRSName = GML_ExtractSrsNameFromGeometry(papsGeometry, osWork, FALSE);
892 : // if (pszSRSName != NULL)
893 : // m_bCanUseGlobalSRSName = FALSE;
894 1 : poClass->MergeSRSName(pszSRSName);
895 :
896 : // Merge geometry type into layer.
897 1 : if( poClass->GetFeatureCount() == 1 && eGType == wkbUnknown )
898 1 : eGType = wkbNone;
899 :
900 : poClass->SetGeometryType(
901 : (int) OGRMergeGeometryTypes(
902 1 : eGType, poGeometry->getGeometryType() ) );
903 :
904 : // merge extents.
905 1 : poGeometry->getEnvelope( &sEnvelope );
906 1 : delete poGeometry;
907 1 : if( poClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax) )
908 : {
909 0 : dfXMin = MIN(dfXMin,sEnvelope.MinX);
910 0 : dfXMax = MAX(dfXMax,sEnvelope.MaxX);
911 0 : dfYMin = MIN(dfYMin,sEnvelope.MinY);
912 0 : dfYMax = MAX(dfYMax,sEnvelope.MaxY);
913 : }
914 : else
915 : {
916 1 : dfXMin = sEnvelope.MinX;
917 1 : dfXMax = sEnvelope.MaxX;
918 1 : dfYMin = sEnvelope.MinY;
919 1 : dfYMax = sEnvelope.MaxY;
920 : }
921 :
922 1 : poClass->SetExtents( dfXMin, dfXMax, dfYMin, dfYMax );
923 : }
924 : else
925 : {
926 4 : if( poClass->GetGeometryType() == (int) wkbUnknown
927 : && poClass->GetFeatureCount() == 1 )
928 2 : poClass->SetGeometryType( wkbNone );
929 : }
930 : #endif /* def SUPPORT_GEOMETRY */
931 : }
932 :
933 5 : delete poFeature;
934 : }
935 :
936 3 : CleanupParser();
937 :
938 3 : return GetClassCount() > 0;
939 : }
940 :
941 : /************************************************************************/
942 : /* ResetReading() */
943 : /************************************************************************/
944 :
945 9 : void NASReader::ResetReading()
946 :
947 : {
948 9 : CleanupParser();
949 9 : SetFilteredClassName(NULL);
950 9 : }
951 :
952 : /************************************************************************/
953 : /* CheckForFID() */
954 : /* */
955 : /* Merge the fid attribute into the current field text. */
956 : /************************************************************************/
957 :
958 6 : void NASReader::CheckForFID( const Attributes &attrs,
959 : char **ppszCurField )
960 :
961 : {
962 : int nIndex;
963 : XMLCh Name[100];
964 :
965 6 : tr_strcpy( Name, "fid" );
966 6 : nIndex = attrs.getIndex( Name );
967 :
968 6 : if( nIndex != -1 )
969 : {
970 6 : char *pszFID = tr_strdup( attrs.getValue( nIndex ) );
971 6 : CPLString osCurField = *ppszCurField;
972 :
973 6 : osCurField += pszFID;
974 6 : CPLFree( pszFID );
975 :
976 6 : CPLFree( *ppszCurField );
977 6 : *ppszCurField = CPLStrdup(osCurField);
978 : }
979 6 : }
980 :
981 : /************************************************************************/
982 : /* CheckForRelations() */
983 : /************************************************************************/
984 :
985 37877 : void NASReader::CheckForRelations( const char *pszElement,
986 : const Attributes &attrs )
987 :
988 : {
989 37877 : GMLFeature *poFeature = GetState()->m_poFeature;
990 :
991 37877 : CPLAssert( poFeature != NULL );
992 :
993 : int nIndex;
994 : XMLCh Name[100];
995 :
996 37877 : tr_strcpy( Name, "xlink:href" );
997 37877 : nIndex = attrs.getIndex( Name );
998 :
999 37877 : if( nIndex != -1 )
1000 : {
1001 2508 : char *pszHRef = tr_strdup( attrs.getValue( nIndex ) );
1002 :
1003 2508 : if( EQUALN(pszHRef,"urn:adv:oid:", 12 ) )
1004 2508 : poFeature->AddOBProperty( pszElement, pszHRef );
1005 :
1006 2508 : CPLFree( pszHRef );
1007 : }
1008 37877 : }
1009 :
1010 : /************************************************************************/
1011 : /* HugeFileResolver() */
1012 : /* Returns TRUE for success */
1013 : /************************************************************************/
1014 :
1015 0 : int NASReader::HugeFileResolver( const char *pszFile,
1016 : int bSqliteIsTempFile,
1017 : int iSqliteCacheMB )
1018 :
1019 : {
1020 0 : CPLDebug( "NAS", "HugeFileResolver() not currently implemented for NAS." );
1021 0 : return FALSE;
1022 : }
1023 :
1024 : /************************************************************************/
1025 : /* PrescanForTemplate() */
1026 : /* Returns TRUE for success */
1027 : /************************************************************************/
1028 :
1029 0 : int NASReader::PrescanForTemplate( void )
1030 :
1031 : {
1032 0 : CPLDebug( "NAS", "PrescanForTemplate() not currently implemented for NAS." );
1033 0 : return FALSE;
1034 : }
1035 :
1036 : /************************************************************************/
1037 : /* ResolveXlinks() */
1038 : /* Returns TRUE for success */
1039 : /************************************************************************/
1040 :
1041 0 : int NASReader::ResolveXlinks( const char *pszFile,
1042 : int* pbOutIsTempFile,
1043 : char **papszSkip,
1044 : const int bStrict )
1045 :
1046 : {
1047 0 : CPLDebug( "NAS", "ResolveXlinks() not currently implemented for NAS." );
1048 0 : return FALSE;
1049 : }
1050 :
1051 : /************************************************************************/
1052 : /* SetFilteredClassName() */
1053 : /************************************************************************/
1054 :
1055 17 : int NASReader::SetFilteredClassName(const char* pszClassName)
1056 : {
1057 17 : CPLFree(m_pszFilteredClassName);
1058 17 : m_pszFilteredClassName = (pszClassName) ? CPLStrdup(pszClassName) : NULL;
1059 17 : return TRUE;
1060 : }
|