void gmlUpdateFeatureClasses ( GFSTemplateList *pCC, GMLReader *pReader, int *pbSequentialLayers ) { /* updating the FeatureClass list */ int clIdx; for (clIdx = 0; clIdx < pReader->GetClassCount(); clIdx++) { GMLFeatureClass* poClass = pReader->GetClass( clIdx ); if (poClass != NULL) poClass->SetFeatureCount( 0 ); } int m_bValid = FALSE; GFSTemplateItem *pItem = pCC->GetFirst(); while ( pItem != NULL ) { /* updating Classes */ GMLFeatureClass* poClass = pReader->GetClass( pItem->GetName() ); if (poClass != NULL) { poClass->SetFeatureCount( pItem->GetCount() ); if ( pItem->GetGeomCount() != 0 && poClass->GetGeometryPropertyCount() == 0 ) poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( "", "", wkbUnknown ) ); m_bValid = TRUE; } pItem = pItem->GetNext(); } if ( m_bValid == TRUE && pCC->HaveSequentialLayers() == TRUE ) *pbSequentialLayers = TRUE; }
static GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode, const char* pszName, CPLXMLNode *psComplexType) { /* -------------------------------------------------------------------- */ /* Grab the sequence of extensions greatgrandchild. */ /* -------------------------------------------------------------------- */ CPLXMLNode *psAttrSeq = CPLGetXMLNode( psComplexType, "complexContent.extension.sequence" ); if( psAttrSeq == NULL ) { return NULL; } /* -------------------------------------------------------------------- */ /* We are pretty sure this going to be a valid Feature class */ /* now, so create it. */ /* -------------------------------------------------------------------- */ GMLFeatureClass *poClass = new GMLFeatureClass( pszName ); /* -------------------------------------------------------------------- */ /* Loop over each of the attribute elements being defined for */ /* this feature class. */ /* -------------------------------------------------------------------- */ int nAttributeIndex = 0; bool bGotUnrecognizedType = false; CPLXMLNode *psAttrDef = psAttrSeq->psChild; for( ; psAttrDef != NULL; psAttrDef = psAttrDef->psNext ) { if( strcmp(psAttrDef->pszValue,"group") == 0 ) { /* Too complex schema for us. Aborts parsing */ delete poClass; return NULL; } /* Parse stuff like : <xs:choice> <xs:element ref="gml:polygonProperty"/> <xs:element ref="gml:multiPolygonProperty"/> </xs:choice> as found in https://downloadagiv.blob.core.windows.net/overstromingsgebieden-en-oeverzones/2014_01/Overstromingsgebieden_en_oeverzones_2014_01_GML.zip */ if( strcmp(psAttrDef->pszValue,"choice") == 0 ) { CPLXMLNode* psChild = psAttrDef->psChild; bool bPolygon = false; bool bMultiPolygon = false; for( ; psChild; psChild = psChild->psNext ) { if( psChild->eType != CXT_Element ) continue; if( strcmp(psChild->pszValue,"element") == 0 ) { const char* pszRef = CPLGetXMLValue( psChild, "ref", NULL ); if( pszRef != NULL ) { if( strcmp(pszRef, "gml:polygonProperty") == 0 ) bPolygon = true; else if( strcmp(pszRef, "gml:multiPolygonProperty") == 0 ) bMultiPolygon = true; else { delete poClass; return NULL; } } else { delete poClass; return NULL; } } } if( bPolygon && bMultiPolygon ) { poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( "", "", wkbMultiPolygon, nAttributeIndex, true ) ); nAttributeIndex ++; } continue; } if( !EQUAL(psAttrDef->pszValue,"element") ) continue; /* MapServer WFS writes element type as an attribute of element */ /* not as a simpleType definition */ const char* pszType = CPLGetXMLValue( psAttrDef, "type", NULL ); const char* pszElementName = CPLGetXMLValue( psAttrDef, "name", NULL ); bool bNullable = EQUAL(CPLGetXMLValue( psAttrDef, "minOccurs", "1" ), "0"); const char* pszMaxOccurs = CPLGetXMLValue( psAttrDef, "maxOccurs", NULL ); if (pszType != NULL) { const char* pszStrippedNSType = StripNS(pszType); int nWidth = 0, nPrecision = 0; GMLPropertyType gmlType = GMLPT_Untyped; if (EQUAL(pszStrippedNSType, "string") || EQUAL(pszStrippedNSType, "Character")) gmlType = GMLPT_String; /* TODO: Would be nice to have a proper date type */ else if (EQUAL(pszStrippedNSType, "date") || EQUAL(pszStrippedNSType, "dateTime")) gmlType = GMLPT_String; else if (EQUAL(pszStrippedNSType, "real") || EQUAL(pszStrippedNSType, "double") || EQUAL(pszStrippedNSType, "decimal")) gmlType = GMLPT_Real; else if (EQUAL(pszStrippedNSType, "float") ) gmlType = GMLPT_Float; else if (EQUAL(pszStrippedNSType, "int") || EQUAL(pszStrippedNSType, "integer")) gmlType = GMLPT_Integer; else if (EQUAL(pszStrippedNSType, "long")) gmlType = GMLPT_Integer64; else if (EQUAL(pszStrippedNSType, "short") ) gmlType = GMLPT_Short; else if (EQUAL(pszStrippedNSType, "boolean") ) gmlType = GMLPT_Boolean; else if (strcmp(pszType, "gml:FeaturePropertyType") == 0 ) { gmlType = GMLPT_FeatureProperty; } else if (STARTS_WITH(pszType, "gml:")) { const AssocNameType* psIter = apsPropertyTypes; while(psIter->pszName) { if (strncmp(pszType + 4, psIter->pszName, strlen(psIter->pszName)) == 0) { OGRwkbGeometryType eType = psIter->eType; /* Look if there's a comment restricting to subclasses */ if( psAttrDef->psNext != NULL && psAttrDef->psNext->eType == CXT_Comment ) { if( strstr(psAttrDef->psNext->pszValue, "restricted to Polygon") ) eType = wkbPolygon; else if( strstr(psAttrDef->psNext->pszValue, "restricted to LineString") ) eType = wkbLineString; else if( strstr(psAttrDef->psNext->pszValue, "restricted to MultiPolygon") ) eType = wkbMultiPolygon; else if( strstr(psAttrDef->psNext->pszValue, "restricted to MultiLineString") ) eType = wkbMultiLineString; } poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( pszElementName, pszElementName, eType, nAttributeIndex, bNullable ) ); nAttributeIndex ++; break; } psIter ++; } if (psIter->pszName == NULL) { /* Can be a non geometry gml type */ /* Too complex schema for us. Aborts parsing */ delete poClass; return NULL; } if (poClass->GetGeometryPropertyCount() == 0) bGotUnrecognizedType = true; continue; } /* Integraph stuff */ else if (strcmp(pszType, "G:Point_MultiPointPropertyType") == 0 || strcmp(pszType, "gmgml:Point_MultiPointPropertyType") == 0) { poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( pszElementName, pszElementName, wkbMultiPoint, nAttributeIndex, bNullable ) ); nAttributeIndex ++; continue; } else if (strcmp(pszType, "G:LineString_MultiLineStringPropertyType") == 0 || strcmp(pszType, "gmgml:LineString_MultiLineStringPropertyType") == 0) { poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( pszElementName, pszElementName, wkbMultiLineString, nAttributeIndex, bNullable ) ); nAttributeIndex ++; continue; } else if (strcmp(pszType, "G:Polygon_MultiPolygonPropertyType") == 0 || strcmp(pszType, "gmgml:Polygon_MultiPolygonPropertyType") == 0 || strcmp(pszType, "gmgml:Polygon_Surface_MultiSurface_CompositeSurfacePropertyType") == 0) { poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( pszElementName, pszElementName, wkbMultiPolygon, nAttributeIndex, bNullable ) ); nAttributeIndex ++; continue; } /* ERDAS Apollo stuff (like in http://apollo.erdas.com/erdas-apollo/vector/WORLDWIDE?SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType&TYPENAME=wfs:cntry98) */ else if (strcmp(pszType, "wfs:MixedPolygonPropertyType") == 0) { poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( pszElementName, pszElementName, wkbMultiPolygon, nAttributeIndex, bNullable) ); nAttributeIndex ++; continue; } else { gmlType = GMLPT_Untyped; if ( ! LookForSimpleType(psSchemaNode, pszStrippedNSType, &gmlType, &nWidth, &nPrecision) ) { /* Too complex schema for us. Aborts parsing */ delete poClass; return NULL; } } if (pszElementName == NULL) pszElementName = "unnamed"; const char* pszPropertyName = pszElementName; if( gmlType == GMLPT_FeatureProperty ) { pszPropertyName = CPLSPrintf("%s_href", pszElementName); } GMLPropertyDefn *poProp = new GMLPropertyDefn( pszPropertyName, pszElementName ); if( pszMaxOccurs != NULL && strcmp(pszMaxOccurs, "1") != 0 ) gmlType = GetListTypeFromSingleType(gmlType); poProp->SetType( gmlType ); poProp->SetWidth( nWidth ); poProp->SetPrecision( nPrecision ); poProp->SetNullable( bNullable ); if (poClass->AddProperty( poProp ) < 0) delete poProp; else nAttributeIndex ++; continue; } // For now we skip geometries .. fixup later. CPLXMLNode* psSimpleType = CPLGetXMLNode( psAttrDef, "simpleType" ); if( psSimpleType == NULL ) { const char* pszRef = CPLGetXMLValue( psAttrDef, "ref", NULL ); /* FME .xsd */ if (pszRef != NULL && STARTS_WITH(pszRef, "gml:")) { const AssocNameType* psIter = apsRefTypes; while(psIter->pszName) { if (strncmp(pszRef + 4, psIter->pszName, strlen(psIter->pszName)) == 0) { if (poClass->GetGeometryPropertyCount() > 0) { OGRwkbGeometryType eNewType = psIter->eType; OGRwkbGeometryType eOldType = (OGRwkbGeometryType)poClass->GetGeometryProperty(0)->GetType(); if ((eNewType == wkbMultiPoint && eOldType == wkbPoint) || (eNewType == wkbMultiLineString && eOldType == wkbLineString) || (eNewType == wkbMultiPolygon && eOldType == wkbPolygon)) { poClass->GetGeometryProperty(0)->SetType(eNewType); } else { CPLDebug("GML", "Geometry field already found ! Ignoring the following ones"); } } else { poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( pszElementName, pszElementName, psIter->eType, nAttributeIndex, true ) ); nAttributeIndex ++; } break; } psIter ++; } if (psIter->pszName == NULL) { /* Can be a non geometry gml type */ /* Too complex schema for us. Aborts parsing */ delete poClass; return NULL; } if (poClass->GetGeometryPropertyCount() == 0) bGotUnrecognizedType = true; continue; } /* Parse stuff like the following found in http://199.29.1.81:8181/miwfs/GetFeature.ashx?REQUEST=GetFeature&MAXFEATURES=1&SERVICE=WFS&VERSION=1.0.0&TYPENAME=miwfs:World : <xs:element name="Obj" minOccurs="0" maxOccurs="1"> <xs:complexType> <xs:sequence> <xs:element ref="gml:_Geometry"/> </xs:sequence> </xs:complexType> </xs:element> */ CPLXMLNode* l_psComplexType = GetSingleChildElement( psAttrDef, "complexType" ); CPLXMLNode* psComplexTypeSequence = GetSingleChildElement( l_psComplexType, "sequence" ); CPLXMLNode* psComplexTypeSequenceElement = GetSingleChildElement( psComplexTypeSequence, "element" ); if( pszElementName != NULL && CheckMinMaxOccursCardinality(psAttrDef) && psComplexTypeSequenceElement != NULL && CheckMinMaxOccursCardinality(psComplexTypeSequence) && strcmp(CPLGetXMLValue( psComplexTypeSequenceElement, "ref", "" ), "gml:_Geometry") == 0 ) { poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( pszElementName, pszElementName, wkbUnknown, nAttributeIndex, bNullable ) ); nAttributeIndex ++; continue; } else { /* Too complex schema for us. Aborts parsing */ delete poClass; return NULL; } } if (pszElementName == NULL) pszElementName = "unnamed"; GMLPropertyDefn *poProp = new GMLPropertyDefn( pszElementName, pszElementName ); GMLPropertyType eType = GMLPT_Untyped; int nWidth = 0, nPrecision = 0; GetSimpleTypeProperties(psSimpleType, &eType, &nWidth, &nPrecision); if( pszMaxOccurs != NULL && strcmp(pszMaxOccurs, "1") != 0 ) eType = GetListTypeFromSingleType(eType); poProp->SetType( eType ); poProp->SetWidth( nWidth ); poProp->SetPrecision( nPrecision ); poProp->SetNullable( bNullable ); if (poClass->AddProperty( poProp ) < 0) delete poProp; else nAttributeIndex ++; } /* If we have found an unknown types, let's be on the side of caution and */ /* create a geometry field */ if( poClass->GetGeometryPropertyCount() == 0 && bGotUnrecognizedType ) { poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( "", "", wkbUnknown, -1, true ) ); } /* -------------------------------------------------------------------- */ /* Class complete, add to reader class list. */ /* -------------------------------------------------------------------- */ poClass->SetSchemaLocked( true ); return poClass; }
int NASReader::PrescanForSchema( int bGetExtents, CPL_UNUSED int bAnalyzeSRSPerFeature, CPL_UNUSED int bOnlyDetectSRS ) { GMLFeature *poFeature; if( m_pszFilename == NULL ) return FALSE; SetClassListLocked( FALSE ); ClearClasses(); if( !SetupParser() ) return FALSE; std::string osWork; while( (poFeature = NextFeature()) != NULL ) { GMLFeatureClass *poClass = poFeature->GetClass(); if( poClass->GetFeatureCount() == -1 ) poClass->SetFeatureCount( 1 ); else poClass->SetFeatureCount( poClass->GetFeatureCount() + 1 ); #ifdef SUPPORT_GEOMETRY if( bGetExtents ) { OGRGeometry *poGeometry = NULL; const CPLXMLNode* const * papsGeometry = poFeature->GetGeometryList(); if( papsGeometry[0] != NULL ) { poGeometry = (OGRGeometry*) OGR_G_CreateFromGMLTree(papsGeometry[0]); poGeometry = ConvertGeometry(poGeometry); } if( poGeometry != NULL ) { double dfXMin, dfXMax, dfYMin, dfYMax; OGREnvelope sEnvelope; if( poClass->GetGeometryPropertyCount() == 0 ) poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( "", "", wkbUnknown, -1, TRUE ) ); OGRwkbGeometryType eGType = (OGRwkbGeometryType) poClass->GetGeometryProperty(0)->GetType(); // Merge SRSName into layer. const char* pszSRSName = GML_ExtractSrsNameFromGeometry(papsGeometry, osWork, FALSE); // if (pszSRSName != NULL) // m_bCanUseGlobalSRSName = FALSE; poClass->MergeSRSName(pszSRSName); // Merge geometry type into layer. if( poClass->GetFeatureCount() == 1 && eGType == wkbUnknown ) eGType = wkbNone; poClass->GetGeometryProperty(0)->SetType( (int) OGRMergeGeometryTypesEx( eGType, poGeometry->getGeometryType(), TRUE ) ); // merge extents. poGeometry->getEnvelope( &sEnvelope ); delete poGeometry; if( poClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax) ) { dfXMin = MIN(dfXMin,sEnvelope.MinX); dfXMax = MAX(dfXMax,sEnvelope.MaxX); dfYMin = MIN(dfYMin,sEnvelope.MinY); dfYMax = MAX(dfYMax,sEnvelope.MaxY); } else { dfXMin = sEnvelope.MinX; dfXMax = sEnvelope.MaxX; dfYMin = sEnvelope.MinY; dfYMax = sEnvelope.MaxY; } poClass->SetExtents( dfXMin, dfXMax, dfYMin, dfYMax ); } else { if( poClass->GetGeometryPropertyCount() == 1 && poClass->GetGeometryProperty(0)->GetType() == (int) wkbUnknown && poClass->GetFeatureCount() == 1 ) { poClass->ClearGeometryProperties(); } } #endif /* def SUPPORT_GEOMETRY */ } delete poFeature; } CleanupParser(); return GetClassCount() > 0; }