geopython / OWSLib

OWSLib is a Python package for client programming with Open Geospatial Consortium (OGC) web service (hence OWS) interface standards, and their related content models.
https://owslib.readthedocs.io
BSD 3-Clause "New" or "Revised" License
390 stars 277 forks source link

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

Closed brentfraser closed 2 weeks ago

brentfraser commented 4 years ago

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 + ":", "")
wietmazairac commented 4 years ago

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'
brentfraser commented 4 years ago

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']}
grmpfhmbl commented 2 years ago

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

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.

github-actions[bot] commented 1 month ago

This Issue has been inactive for 90 days. In order to manage maintenance burden, it will be automatically closed in 7 days.

github-actions[bot] commented 2 weeks ago

This Issue has been closed due to there being no activity for more than 90 days.