OWSLib
OWSLib copied to clipboard
WFS service: construct_schema fails if there is no schema in the layer name
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 + ":", "")
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'
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']}
#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.