1 : /******************************************************************************
2 : * $Id: parsexsd.cpp 23748 2012-01-12 23:34:27Z rouault $
3 : *
4 : * Project: GML Reader
5 : * Purpose: Implementation of GMLParseXSD()
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2005, 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 "parsexsd.h"
31 : #include "cpl_error.h"
32 : #include "cpl_conv.h"
33 : #include "ogr_core.h"
34 :
35 : /************************************************************************/
36 : /* StripNS() */
37 : /* */
38 : /* Return potentially shortened form of string with namespace */
39 : /* stripped off if there is one. Returns pointer into */
40 : /* original string. */
41 : /************************************************************************/
42 :
43 1572 : const char *StripNS( const char *pszFullValue )
44 :
45 : {
46 1572 : const char *pszColon = strstr( pszFullValue, ":" );
47 1572 : if( pszColon == NULL )
48 926 : return pszFullValue;
49 : else
50 646 : return pszColon + 1;
51 : }
52 :
53 : /************************************************************************/
54 : /* GetSimpleTypeProperties() */
55 : /************************************************************************/
56 :
57 : static
58 70 : int GetSimpleTypeProperties(CPLXMLNode *psTypeNode,
59 : GMLPropertyType *pGMLType,
60 : int *pnWidth,
61 : int *pnPrecision)
62 : {
63 : const char *pszBase =
64 : StripNS( CPLGetXMLValue( psTypeNode,
65 70 : "restriction.base", "" ));
66 :
67 70 : if( EQUAL(pszBase,"decimal") )
68 : {
69 24 : *pGMLType = GMLPT_Real;
70 : const char *pszWidth =
71 : CPLGetXMLValue( psTypeNode,
72 24 : "restriction.totalDigits.value", "0" );
73 : const char *pszPrecision =
74 : CPLGetXMLValue( psTypeNode,
75 24 : "restriction.fractionDigits.value", "0" );
76 24 : *pnWidth = atoi(pszWidth);
77 24 : *pnPrecision = atoi(pszPrecision);
78 24 : return TRUE;
79 : }
80 :
81 46 : else if( EQUAL(pszBase,"float")
82 : || EQUAL(pszBase,"double") )
83 : {
84 0 : *pGMLType = GMLPT_Real;
85 0 : return TRUE;
86 : }
87 :
88 46 : else if( EQUAL(pszBase,"integer") )
89 : {
90 16 : *pGMLType = GMLPT_Integer;
91 : const char *pszWidth =
92 : CPLGetXMLValue( psTypeNode,
93 16 : "restriction.totalDigits.value", "0" );
94 16 : *pnWidth = atoi(pszWidth);
95 16 : return TRUE;
96 : }
97 :
98 30 : else if( EQUAL(pszBase,"string") )
99 : {
100 30 : *pGMLType = GMLPT_String;
101 : const char *pszWidth =
102 : CPLGetXMLValue( psTypeNode,
103 30 : "restriction.maxLength.value", "0" );
104 30 : *pnWidth = atoi(pszWidth);
105 30 : return TRUE;
106 : }
107 :
108 : /* TODO: Would be nice to have a proper date type */
109 0 : else if( EQUAL(pszBase,"date") ||
110 : EQUAL(pszBase,"dateTime") )
111 : {
112 0 : *pGMLType = GMLPT_String;
113 0 : return TRUE;
114 : }
115 0 : return FALSE;
116 : }
117 :
118 : /************************************************************************/
119 : /* LookForSimpleType() */
120 : /************************************************************************/
121 :
122 : static
123 2 : int LookForSimpleType(CPLXMLNode *psSchemaNode,
124 : const char* pszStrippedNSType,
125 : GMLPropertyType *pGMLType,
126 : int *pnWidth,
127 : int *pnPrecision)
128 : {
129 : CPLXMLNode *psThis;
130 20 : for( psThis = psSchemaNode->psChild;
131 : psThis != NULL; psThis = psThis->psNext )
132 : {
133 20 : if( psThis->eType == CXT_Element
134 : && EQUAL(psThis->pszValue,"simpleType")
135 : && EQUAL(CPLGetXMLValue(psThis,"name",""),pszStrippedNSType) )
136 : {
137 2 : break;
138 : }
139 : }
140 2 : if (psThis == NULL)
141 0 : return FALSE;
142 :
143 2 : return GetSimpleTypeProperties(psThis, pGMLType, pnWidth, pnPrecision);
144 : }
145 :
146 : /************************************************************************/
147 : /* ParseFeatureType() */
148 : /************************************************************************/
149 :
150 : typedef struct
151 : {
152 : const char* pszName;
153 : OGRwkbGeometryType eType;
154 : } AssocNameType;
155 :
156 : static const AssocNameType apsPropertyTypes [] =
157 : {
158 : {"GeometryPropertyType", wkbUnknown},
159 : {"PointPropertyType", wkbPoint},
160 : {"LineStringPropertyType", wkbLineString},
161 : {"CurvePropertyType", wkbLineString},
162 : {"PolygonPropertyType", wkbPolygon},
163 : {"SurfacePropertyType", wkbPolygon},
164 : {"MultiPointPropertyType", wkbMultiPoint},
165 : {"MultiLineStringPropertyType", wkbMultiLineString},
166 : {"MultiCurvePropertyType", wkbMultiLineString},
167 : {"MultiPolygonPropertyType", wkbMultiPolygon},
168 : {"MultiSurfacePropertyType", wkbMultiPolygon},
169 : {"MultiGeometryPropertyType", wkbGeometryCollection},
170 : {NULL, wkbUnknown},
171 : };
172 :
173 : /* Found in FME .xsd (e.g. <element ref="gml:curveProperty" minOccurs="0"/>) */
174 : static const AssocNameType apsRefTypes [] =
175 : {
176 : {"pointProperty", wkbPoint},
177 : {"curveProperty", wkbLineString},
178 : {"surfaceProperty", wkbPolygon},
179 : {"multiPointProperty", wkbMultiPoint},
180 : {"multiCurveProperty", wkbMultiLineString},
181 : {"multiSurfaceProperty", wkbMultiPolygon},
182 : {NULL, wkbUnknown},
183 : };
184 :
185 : static
186 : GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
187 : const char* pszName,
188 : CPLXMLNode *psThis);
189 :
190 : static
191 92 : GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
192 : const char* pszName,
193 : const char *pszType)
194 : {
195 : CPLXMLNode *psThis;
196 1156 : for( psThis = psSchemaNode->psChild;
197 : psThis != NULL; psThis = psThis->psNext )
198 : {
199 1156 : if( psThis->eType == CXT_Element
200 : && EQUAL(psThis->pszValue,"complexType")
201 : && EQUAL(CPLGetXMLValue(psThis,"name",""),pszType) )
202 : {
203 92 : break;
204 : }
205 : }
206 92 : if (psThis == NULL)
207 0 : return NULL;
208 :
209 92 : return GMLParseFeatureType(psSchemaNode, pszName, psThis);
210 : }
211 :
212 :
213 : static
214 240 : GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
215 : const char* pszName,
216 : CPLXMLNode *psComplexType)
217 : {
218 :
219 : /* -------------------------------------------------------------------- */
220 : /* Grab the sequence of extensions greatgrandchild. */
221 : /* -------------------------------------------------------------------- */
222 : CPLXMLNode *psAttrSeq =
223 : CPLGetXMLNode( psComplexType,
224 240 : "complexContent.extension.sequence" );
225 :
226 240 : if( psAttrSeq == NULL )
227 : {
228 0 : return NULL;
229 : }
230 :
231 : /* -------------------------------------------------------------------- */
232 : /* We are pretty sure this going to be a valid Feature class */
233 : /* now, so create it. */
234 : /* -------------------------------------------------------------------- */
235 240 : GMLFeatureClass *poClass = new GMLFeatureClass( pszName );
236 :
237 : /* -------------------------------------------------------------------- */
238 : /* Loop over each of the attribute elements being defined for */
239 : /* this feature class. */
240 : /* -------------------------------------------------------------------- */
241 : CPLXMLNode *psAttrDef;
242 240 : int nAttributeIndex = 0;
243 :
244 240 : int bGotUnrecognizedType = FALSE;
245 :
246 1568 : for( psAttrDef = psAttrSeq->psChild;
247 : psAttrDef != NULL;
248 : psAttrDef = psAttrDef->psNext )
249 : {
250 1328 : if( strcmp(psAttrDef->pszValue,"group") == 0 )
251 : {
252 : /* Too complex schema for us. Aborts parsing */
253 0 : delete poClass;
254 0 : return NULL;
255 : }
256 :
257 1328 : if( !EQUAL(psAttrDef->pszValue,"element") )
258 0 : continue;
259 :
260 : /* MapServer WFS writes element type as an attribute of element */
261 : /* not as a simpleType definition */
262 1328 : const char* pszType = CPLGetXMLValue( psAttrDef, "type", NULL );
263 1328 : const char* pszElementName = CPLGetXMLValue( psAttrDef, "name", NULL );
264 1328 : if (pszType != NULL)
265 : {
266 1224 : const char* pszStrippedNSType = StripNS(pszType);
267 1224 : int nWidth = 0, nPrecision = 0;
268 :
269 1224 : GMLPropertyType gmlType = GMLPT_Untyped;
270 1566 : if (EQUAL(pszStrippedNSType, "string") ||
271 : EQUAL(pszStrippedNSType, "Character"))
272 342 : gmlType = GMLPT_String;
273 : /* TODO: Would be nice to have a proper date type */
274 882 : else if (EQUAL(pszStrippedNSType, "date") ||
275 : EQUAL(pszStrippedNSType, "dateTime"))
276 0 : gmlType = GMLPT_String;
277 1474 : else if (EQUAL(pszStrippedNSType, "real") ||
278 : EQUAL(pszStrippedNSType, "double") ||
279 : EQUAL(pszStrippedNSType, "float") ||
280 : EQUAL(pszStrippedNSType, "decimal"))
281 592 : gmlType = GMLPT_Real;
282 358 : else if (EQUAL(pszStrippedNSType, "short") ||
283 : EQUAL(pszStrippedNSType, "int") ||
284 : EQUAL(pszStrippedNSType, "integer") ||
285 : EQUAL(pszStrippedNSType, "long"))
286 68 : gmlType = GMLPT_Integer;
287 222 : else if (strncmp(pszType, "gml:", 4) == 0)
288 : {
289 220 : const AssocNameType* psIter = apsPropertyTypes;
290 1588 : while(psIter->pszName)
291 : {
292 1368 : if (strncmp(pszType + 4, psIter->pszName, strlen(psIter->pszName)) == 0)
293 : {
294 220 : if (poClass->GetGeometryAttributeIndex() != -1)
295 : {
296 0 : CPLDebug("GML", "Geometry field already found ! Ignoring the following ones");
297 : }
298 : else
299 : {
300 220 : poClass->SetGeometryElement(pszElementName);
301 220 : poClass->SetGeometryType(psIter->eType);
302 220 : poClass->SetGeometryAttributeIndex( nAttributeIndex );
303 :
304 220 : nAttributeIndex ++;
305 : }
306 :
307 220 : break;
308 : }
309 :
310 1148 : psIter ++;
311 : }
312 :
313 220 : if (psIter->pszName == NULL)
314 : {
315 : /* Can be a non geometry gml type */
316 : /* Too complex schema for us. Aborts parsing */
317 0 : delete poClass;
318 0 : return NULL;
319 : }
320 :
321 220 : if (poClass->GetGeometryAttributeIndex() == -1)
322 0 : bGotUnrecognizedType = TRUE;
323 :
324 220 : continue;
325 : }
326 :
327 : /* Integraph stuff */
328 2 : else if (strcmp(pszType, "G:Point_MultiPointPropertyType") == 0 ||
329 : strcmp(pszType, "gmgml:Point_MultiPointPropertyType") == 0)
330 : {
331 0 : poClass->SetGeometryElement(pszElementName);
332 0 : poClass->SetGeometryType(wkbMultiPoint);
333 0 : poClass->SetGeometryAttributeIndex( nAttributeIndex );
334 :
335 0 : nAttributeIndex ++;
336 0 : continue;
337 : }
338 2 : else if (strcmp(pszType, "G:LineString_MultiLineStringPropertyType") == 0 ||
339 : strcmp(pszType, "gmgml:LineString_MultiLineStringPropertyType") == 0)
340 : {
341 0 : poClass->SetGeometryElement(pszElementName);
342 0 : poClass->SetGeometryType(wkbMultiLineString);
343 0 : poClass->SetGeometryAttributeIndex( nAttributeIndex );
344 :
345 0 : nAttributeIndex ++;
346 0 : continue;
347 : }
348 2 : else if (strcmp(pszType, "G:Polygon_MultiPolygonPropertyType") == 0 ||
349 : strcmp(pszType, "gmgml:Polygon_MultiPolygonPropertyType") == 0 ||
350 : strcmp(pszType, "gmgml:Polygon_Surface_MultiSurface_CompositeSurfacePropertyType") == 0)
351 : {
352 0 : poClass->SetGeometryElement(pszElementName);
353 0 : poClass->SetGeometryType(wkbMultiPolygon);
354 0 : poClass->SetGeometryAttributeIndex( nAttributeIndex );
355 :
356 0 : nAttributeIndex ++;
357 0 : continue;
358 : }
359 :
360 : /* ERDAS Apollo stuff (like in http://apollo.erdas.com/erdas-apollo/vector/WORLDWIDE?SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType&TYPENAME=wfs:cntry98) */
361 2 : else if (strcmp(pszType, "wfs:MixedPolygonPropertyType") == 0)
362 : {
363 0 : poClass->SetGeometryElement(pszElementName);
364 0 : poClass->SetGeometryType(wkbMultiPolygon);
365 0 : poClass->SetGeometryAttributeIndex( nAttributeIndex );
366 :
367 0 : nAttributeIndex ++;
368 0 : continue;
369 : }
370 :
371 : else
372 : {
373 2 : gmlType = GMLPT_Untyped;
374 2 : if ( ! LookForSimpleType(psSchemaNode, pszStrippedNSType,
375 : &gmlType, &nWidth, &nPrecision) )
376 : {
377 : /* Too complex schema for us. Aborts parsing */
378 0 : delete poClass;
379 0 : return NULL;
380 : }
381 : }
382 :
383 1004 : if (pszElementName == NULL)
384 0 : pszElementName = "unnamed";
385 : GMLPropertyDefn *poProp = new GMLPropertyDefn(
386 1004 : pszElementName, pszElementName );
387 :
388 1004 : poProp->SetType( gmlType );
389 1004 : poProp->SetAttributeIndex( nAttributeIndex );
390 1004 : poProp->SetWidth( nWidth );
391 1004 : poProp->SetPrecision( nPrecision );
392 :
393 1004 : if (poClass->AddProperty( poProp ) < 0)
394 0 : delete poProp;
395 : else
396 1004 : nAttributeIndex ++;
397 :
398 1004 : continue;
399 : }
400 :
401 : // For now we skip geometries .. fixup later.
402 104 : CPLXMLNode* psSimpleType = CPLGetXMLNode( psAttrDef, "simpleType" );
403 104 : if( psSimpleType == NULL )
404 : {
405 36 : const char* pszRef = CPLGetXMLValue( psAttrDef, "ref", NULL );
406 :
407 : /* FME .xsd */
408 36 : if (pszRef != NULL && strncmp(pszRef, "gml:", 4) == 0)
409 : {
410 36 : const AssocNameType* psIter = apsRefTypes;
411 162 : while(psIter->pszName)
412 : {
413 126 : if (strncmp(pszRef + 4, psIter->pszName, strlen(psIter->pszName)) == 0)
414 : {
415 36 : if (poClass->GetGeometryAttributeIndex() != -1)
416 : {
417 18 : OGRwkbGeometryType eNewType = psIter->eType;
418 18 : OGRwkbGeometryType eOldType = (OGRwkbGeometryType)poClass->GetGeometryType();
419 36 : if ((eNewType == wkbMultiPoint && eOldType == wkbPoint) ||
420 : (eNewType == wkbMultiLineString && eOldType == wkbLineString) ||
421 : (eNewType == wkbMultiPolygon && eOldType == wkbPolygon))
422 : {
423 18 : poClass->SetGeometryType(eNewType);
424 : }
425 : else
426 : {
427 0 : CPLDebug("GML", "Geometry field already found ! Ignoring the following ones");
428 : }
429 : }
430 : else
431 : {
432 18 : poClass->SetGeometryElement(pszElementName);
433 18 : poClass->SetGeometryType(psIter->eType);
434 18 : poClass->SetGeometryAttributeIndex( nAttributeIndex );
435 :
436 18 : nAttributeIndex ++;
437 : }
438 :
439 36 : break;
440 : }
441 :
442 90 : psIter ++;
443 : }
444 :
445 36 : if (psIter->pszName == NULL)
446 : {
447 : /* Can be a non geometry gml type */
448 : /* Too complex schema for us. Aborts parsing */
449 0 : delete poClass;
450 0 : return NULL;
451 : }
452 :
453 36 : if (poClass->GetGeometryAttributeIndex() == -1)
454 0 : bGotUnrecognizedType = TRUE;
455 :
456 36 : continue;
457 : }
458 : else
459 : {
460 : /* Too complex schema for us. Aborts parsing */
461 0 : delete poClass;
462 0 : return NULL;
463 : }
464 : }
465 :
466 68 : if (pszElementName == NULL)
467 0 : pszElementName = "unnamed";
468 : GMLPropertyDefn *poProp = new GMLPropertyDefn(
469 68 : pszElementName, pszElementName );
470 :
471 68 : GMLPropertyType eType = GMLPT_Untyped;
472 68 : int nWidth = 0, nPrecision = 0;
473 68 : GetSimpleTypeProperties(psSimpleType, &eType, &nWidth, &nPrecision);
474 68 : poProp->SetType( eType );
475 68 : poProp->SetWidth( nWidth );
476 68 : poProp->SetPrecision( nPrecision );
477 68 : poProp->SetAttributeIndex( nAttributeIndex );
478 :
479 68 : if (poClass->AddProperty( poProp ) < 0)
480 0 : delete poProp;
481 : else
482 68 : nAttributeIndex ++;
483 : }
484 :
485 : /* Only report wkbNone if we didn't find a known geometry type */
486 : /* and there were not any unknown types (in case this unknown type */
487 : /* would be a geometry type) */
488 240 : if (poClass->GetGeometryAttributeIndex() == -1 &&
489 : !bGotUnrecognizedType)
490 : {
491 2 : poClass->SetGeometryType(wkbNone);
492 : }
493 :
494 : /* -------------------------------------------------------------------- */
495 : /* Class complete, add to reader class list. */
496 : /* -------------------------------------------------------------------- */
497 240 : poClass->SetSchemaLocked( TRUE );
498 :
499 240 : return poClass;
500 : }
501 :
502 : /************************************************************************/
503 : /* GMLParseXSD() */
504 : /************************************************************************/
505 :
506 164 : int GMLParseXSD( const char *pszFile,
507 : std::vector<GMLFeatureClass*> & aosClasses)
508 :
509 : {
510 164 : if( pszFile == NULL )
511 0 : return FALSE;
512 :
513 : /* -------------------------------------------------------------------- */
514 : /* Load the raw XML file. */
515 : /* -------------------------------------------------------------------- */
516 164 : CPLXMLNode *psXSDTree = CPLParseXMLFile( pszFile );
517 :
518 164 : if( psXSDTree == NULL )
519 0 : return FALSE;
520 :
521 : /* -------------------------------------------------------------------- */
522 : /* Strip off any namespace qualifiers. */
523 : /* -------------------------------------------------------------------- */
524 164 : CPLStripXMLNamespace( psXSDTree, NULL, TRUE );
525 :
526 : /* -------------------------------------------------------------------- */
527 : /* Find <schema> root element. */
528 : /* -------------------------------------------------------------------- */
529 164 : CPLXMLNode *psSchemaNode = CPLGetXMLNode( psXSDTree, "=schema" );
530 164 : if( psSchemaNode == NULL )
531 : {
532 0 : CPLDestroyXMLNode( psXSDTree );
533 0 : return FALSE;
534 : }
535 :
536 : /* ==================================================================== */
537 : /* Process each feature class definition. */
538 : /* ==================================================================== */
539 : CPLXMLNode *psThis;
540 :
541 2028 : for( psThis = psSchemaNode->psChild;
542 : psThis != NULL; psThis = psThis->psNext )
543 : {
544 : /* -------------------------------------------------------------------- */
545 : /* Check for <xs:element> node. */
546 : /* -------------------------------------------------------------------- */
547 1864 : if( psThis->eType != CXT_Element
548 : || !EQUAL(psThis->pszValue,"element") )
549 1586 : continue;
550 :
551 : /* -------------------------------------------------------------------- */
552 : /* Check the substitution group. */
553 : /* -------------------------------------------------------------------- */
554 : const char *pszSubGroup =
555 278 : StripNS(CPLGetXMLValue(psThis,"substitutionGroup",""));
556 :
557 : // Old OGR produced elements for the feature collection.
558 278 : if( EQUAL(pszSubGroup, "_FeatureCollection") )
559 22 : continue;
560 :
561 256 : if( !EQUAL(pszSubGroup, "_Feature") &&
562 : !EQUAL(pszSubGroup, "AbstractFeature") /* AbstractFeature used by GML 3.2 */ )
563 : {
564 10 : continue;
565 : }
566 :
567 : /* -------------------------------------------------------------------- */
568 : /* Get name */
569 : /* -------------------------------------------------------------------- */
570 : const char *pszName;
571 :
572 246 : pszName = CPLGetXMLValue( psThis, "name", NULL );
573 246 : if( pszName == NULL )
574 : {
575 0 : continue;
576 : }
577 :
578 : /* -------------------------------------------------------------------- */
579 : /* Get type and verify relationship with name. */
580 : /* -------------------------------------------------------------------- */
581 : const char *pszType;
582 :
583 246 : pszType = CPLGetXMLValue( psThis, "type", NULL );
584 246 : if (pszType == NULL)
585 : {
586 148 : CPLXMLNode *psComplexType = CPLGetXMLNode( psThis, "complexType" );
587 148 : if (psComplexType)
588 : {
589 : GMLFeatureClass* poClass =
590 148 : GMLParseFeatureType(psSchemaNode, pszName, psComplexType);
591 148 : if (poClass)
592 148 : aosClasses.push_back(poClass);
593 : }
594 148 : continue;
595 : }
596 98 : if( strstr( pszType, ":" ) != NULL )
597 98 : pszType = strstr( pszType, ":" ) + 1;
598 98 : if( EQUAL(pszType, pszName) )
599 : {
600 : /* A few WFS servers return a type name which is the element name */
601 : /* without any _Type or Type suffix */
602 : /* e.g. : http://apollo.erdas.com/erdas-apollo/vector/Cherokee?SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType&TYPENAME=iwfs:Air */
603 : }
604 98 : else if( !EQUALN(pszType,pszName,strlen(pszName))
605 : || !(EQUAL(pszType+strlen(pszName),"_Type") ||
606 : EQUAL(pszType+strlen(pszName),"Type")) )
607 : {
608 0 : continue;
609 : }
610 :
611 : /* CanVec .xsd contains weird types that are not used in the related GML */
612 98 : if (strncmp(pszName, "XyZz", 4) == 0 ||
613 : strncmp(pszName, "XyZ1", 4) == 0 ||
614 : strncmp(pszName, "XyZ2", 4) == 0)
615 6 : continue;
616 :
617 : GMLFeatureClass* poClass =
618 92 : GMLParseFeatureType(psSchemaNode, pszName, pszType);
619 92 : if (poClass)
620 92 : aosClasses.push_back(poClass);
621 : }
622 :
623 164 : CPLDestroyXMLNode( psXSDTree );
624 :
625 164 : if( aosClasses.size() > 0 )
626 : {
627 158 : return TRUE;
628 : }
629 : else
630 6 : return FALSE;
631 : }
|