OWSLib icon indicating copy to clipboard operation
OWSLib copied to clipboard

WFS service: construct_schema fails if there is no schema in the layer name

Open brentfraser opened this issue 5 years ago • 3 comments

I've written a bit of python to get information on a WFS service. OWSLib's _construct_schema fails if there is no schema in the layer name:


C:\>python ows2gm.py -wfs "https://SDMDataAccess.sc.egov.usda.gov/Spatial/SDMWGS84Geographic.wfs" -layerWFS "aoi"

NRCS Soil Data Mart Data Access Web Feature Service WGS84
['GetCapabilities', 'DescribeFeatureType', 'GetFeature']
mapunitpoly
mapunitline
mapunitpoint
mapunitpolyextended
mapunitlineextended
mapunitpointextended
mapunitpolythematic
mapunitlinethematic
mapunitpointthematic
surveyareapoly
surveyareapolytransparent
surveyareapolyoutline
featline
featpoint
aoi
aoihatched
aoilabeled
Traceback (most recent call last):
  File "ows2gm.py", line 83, in <module>
    print(wfs11.get_schema(layerWFS))
  File "C:\Program Files\Python38\lib\site-packages\owslib\feature\__init__.py", line 213, in get_schema
    return get_schema(self.url, typename, self.version, auth=self.auth)
  File "C:\Program Files\Python38\lib\site-packages\owslib\feature\schema.py", line 60, in get_schema
    return _construct_schema(elements, nsmap)
  File "C:\Program Files\Python38\lib\site-packages\owslib\feature\schema.py", line 128, in _construct_schema
    schema["properties"][name] = data_type.replace(schema_key + ":", "")
TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'

The fix (I think) is to add a check at line 128:

            if schema_key is not None:
                schema["properties"][name] = data_type.replace(schema_key + ":", "")

brentfraser avatar Aug 09 '20 17:08 brentfraser

I experience the same problem.

import owslib.wfs

url = 'https://geodata.nationaalgeoregister.nl/bag/wfs/v1_1'
version = '1.1.0'    

wfs = owslib.wfs.WebFeatureService(url = url, version = version)
       
        
title = wfs.identification.title
operations = [operation.name for operation in wfs.operations]
typenames = list(wfs.contents)
wfs.get_schema(typenames[3])
    wfs.get_schema(typenames[3])

  File "C:\ProgramData\Anaconda3\lib\site-packages\owslib\feature\__init__.py", line 213, in get_schema
    return get_schema(self.url, typename, self.version, auth=self.auth)

  File "C:\ProgramData\Anaconda3\lib\site-packages\owslib\feature\schema.py", line 60, in get_schema
    return _construct_schema(elements, nsmap)

  File "C:\ProgramData\Anaconda3\lib\site-packages\owslib\feature\schema.py", line 128, in _construct_schema
    schema["properties"][name] = data_type.replace(schema_key + ":", "")

TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'

wietmazairac avatar Aug 10 '20 07:08 wietmazairac

When I use my fix above and use your WFS url, I get:

Title:
----------
BAG WFS

Operations:
----------
['GetCapabilities', 'DescribeFeatureType', 'GetFeature']

Layers:
----------
bag:ligplaats
bag:pand
bag:standplaats
bag:verblijfsobject
bag:woonplaats

Attributes for "bag:verblijfsobject"
----------
{'geometry': 'GeometryCollection',
 'geometry_column': 'geometrie',
 'properties': {},
 'required': ['geometrie',
              'gid',
              'identificatie',
              'oppervlakte',
              'status',
              'gebruiksdoel',
              'openbare_ruimte',
              'huisnummer',
              'huisletter',
              'toevoeging',
              'postcode',
              'woonplaats',
              'bouwjaar',
              'pandidentificatie',
              'pandstatus',
              'rdf_seealso']}

brentfraser avatar Aug 10 '20 14:08 brentfraser

#702 fixes the exception but not the underlying error. If describeFeatureType returns a schema where xmlns="http://www.w3.org/2001/XMLSchema" and xmlns:xsd="http://www.w3.org/2001/XMLSchema" are specified schema_key might be set to None depending on the order xmlns attributes and no properties will be added to the resulting dict. You can see that in https://github.com/geopython/OWSLib/issues/698#issuecomment-671383167 where we get required columns but no properties.

Example Schema:

<schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" xmlns:qgs="http://www.qgis.org/gml" xmlns:ogc="http://www.opengis.net/ogc" targetNamespace="http://www.qgis.org/gml" version="1.0" elementFormDefault="qualified">
<import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/gml.xsd"/>
<element type="qgs:TestLayerType" substitutionGroup="gml:_Feature" name="TestLayer"/>
<complexType name="TestLayerType">
<complexContent>
<extension base="gml:AbstractFeatureType">
<sequence>
<element maxOccurs="1" type="gml:MultiPolygonPropertyType" minOccurs="0" name="geometry"/>
<element type="long" name="fid"/>
<element nillable="true" type="string" name="id"/>
<element nillable="true" type="string" name="name"/>
</sequence>
</extension>
</complexContent>
</complexType>
</schema>

nsmap will be set to this

{'xsd': 'http://www.w3.org/2001/XMLSchema', None: 'http://www.w3.org/2001/XMLSchema', 'gml':'http://www.opengis.net/gml', 'qgs': 'http://www.qgis.org/gml', 'ogc': 'http://www.opengis.net/ogc'}

what results in the loop in line 98-102 setting schema_key to None

https://github.com/geopython/OWSLib/blob/5ab1139038a1fdd67632c6f5df520fb0157d2f76/owslib/feature/schema.py#L98-L102

This will result in no properties being added here

https://github.com/geopython/OWSLib/blob/5ab1139038a1fdd67632c6f5df520fb0157d2f76/owslib/feature/schema.py#L130-L131

If you switch the order of the xmlns attributes in the schema the properties will be added. Looking at the examples given above the problem there is the same. The URLs I checked where

  • https://sdmdataaccess.sc.egov.usda.gov/Spatial/SDMWGS84Geographic.wfs?service=WFS&version=1.1.0&request=describeFeatureType&typeName=aoi
  • https://geodata.nationaalgeoregister.nl/bag/wfs/v1_1?service=WFS&version=1.1.0&request=describeFeatureType&typeName=bag:verblijfsobject

I don't understand why this namespace searching is done anyways. If you only want to drop the namespace name in front of the type for better readability then why don't you just delete (replace) everything in front of the first ':'?

You might get a similar problem here https://github.com/geopython/OWSLib/blob/5ab1139038a1fdd67632c6f5df520fb0157d2f76/owslib/feature/schema.py#L122 if for whatever reason the server returns a schema where http://www.opengis.net/gml is set as the default namespace.

grmpfhmbl avatar Mar 24 '22 16:03 grmpfhmbl