From 3dab9eb82a361034e2e9072a72ea609a484035c5 Mon Sep 17 00:00:00 2001 From: Kevin Bieri Date: Tue, 11 Aug 2026 16:16:29 +0200 Subject: [PATCH] wfs: Fix error when parsing empty OtherCRS According to the official XSD, `` and `` are valid for WFS capabilities. Previously, the Crs tried to split the id, which may be None in this case and resulted in an error. With this change, both wfs110 and wfs200 reject None values entirely. --- owslib/feature/wfs110.py | 2 +- owslib/feature/wfs200.py | 2 +- ..._empty_other_srs_GetCapabilities_1_1_0.xml | 253 ++++++++++++++++++ ..._empty_other_srs_GetCapabilities_2_0_0.xml | 228 ++++++++++++++++ tests/test_wfs_generic.py | 15 ++ 5 files changed, 498 insertions(+), 2 deletions(-) create mode 100644 tests/resources/wfs_empty_other_srs_GetCapabilities_1_1_0.xml create mode 100644 tests/resources/wfs_empty_other_srs_GetCapabilities_2_0_0.xml diff --git a/owslib/feature/wfs110.py b/owslib/feature/wfs110.py index b19bc990..e4f91956 100644 --- a/owslib/feature/wfs110.py +++ b/owslib/feature/wfs110.py @@ -392,7 +392,7 @@ def __init__(self, elem, parse_remote_metadata=False, timeout=30, headers=None, # crs options self.crsOptions = [ Crs(srs.text) - for srs in elem.findall(nspath_eval("wfs:OtherSRS", namespaces)) + for srs in elem.findall(nspath_eval("wfs:OtherSRS", namespaces)) if srs.text ] dsrs = testXMLValue(elem.find(nspath_eval("wfs:DefaultSRS", namespaces))) if dsrs is not None: # first element is default srs diff --git a/owslib/feature/wfs200.py b/owslib/feature/wfs200.py index 79421f97..a1c6018a 100644 --- a/owslib/feature/wfs200.py +++ b/owslib/feature/wfs200.py @@ -525,7 +525,7 @@ def __init__( self.boundingBoxWGS84 = None # crs options self.crsOptions = [ - Crs(srs.text) for srs in elem.findall(nspath("OtherCRS", ns=WFS_NAMESPACE)) + Crs(srs.text) for srs in elem.findall(nspath("OtherCRS", ns=WFS_NAMESPACE)) if srs.text ] defaultCrs = elem.findall(nspath("DefaultCRS", ns=WFS_NAMESPACE)) if len(defaultCrs) > 0: diff --git a/tests/resources/wfs_empty_other_srs_GetCapabilities_1_1_0.xml b/tests/resources/wfs_empty_other_srs_GetCapabilities_1_1_0.xml new file mode 100644 index 00000000..28a26bad --- /dev/null +++ b/tests/resources/wfs_empty_other_srs_GetCapabilities_1_1_0.xml @@ -0,0 +1,253 @@ + + + + Help Service Gazeteer + Vyhledavani sidel WFS + + Czech republic + gazeeteer + + OGC WFS + 1.1.0 + none + for non profit use + + + Help Service Remote Sensing, ltd. + + + Stanislav Hol� + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WFS + + + 1.0.0 + 1.1.0 + + + text/xml + + + + + + + + + + + XMLSCHEMA + text/xml; subtype=gml/2.1.2 + text/xml; subtype=gml/3.1.1 + + + + + + + + + + + results + hits + + + text/xml; subtype=gml/3.1.1 + + + + 512 + + + + + Query + + + nuts1 + NUTS1 + urn:ogc:def:crs:EPSG::4326 + + + text/xml; subtype=gml/3.1.1 + + + -73.2634725607418 -21.3428428333117 + 120.131330581725 83.6274190882078 + + + + states + states + urn:ogc:def:crs:EPSG::4326 + + + text/xml; subtype=gml/3.1.1 + + + -180 -89.9 + 180 83.674733 + + + + nuts2 + NUTS2 + urn:ogc:def:crs:EPSG::4326 + + + text/xml; subtype=gml/3.1.1 + + + -73.2634725607418 -21.3428428333117 + 120.131330581725 83.6274190882078 + + + + nuts3 + NUTS2 + urn:ogc:def:crs:EPSG::4326 + + + text/xml; subtype=gml/3.1.1 + + + -73.2634725607418 -21.3428428333117 + 120.131330581725 83.6274190882078 + + + + orp + Obce s rozsirenou pusobnosti + urn:ogc:def:crs:EPSG::4326 + + + text/xml; subtype=gml/3.1.1 + + + 12.0971913568792 48.5542371331248 + 18.858466675767 51.055771864485 + + + + okresy + Okresy CR + urn:ogc:def:crs:EPSG::4326 + + + text/xml; subtype=gml/3.1.1 + + + 12.0971913568792 48.5542371331248 + 18.858297034807 51.055771864485 + + + + sidla + Sidla CR + urn:ogc:def:crs:EPSG::4326 + + + text/xml; subtype=gml/3.1.1 + + + 12.0696013961853 48.529730261414 + 18.973334328945 51.0387911057136 + + + + kraje + Kraje CR + urn:ogc:def:crs:EPSG::4326 + + + text/xml; subtype=gml/3.1.1 + + + 12.0977321962419 48.5542371331248 + 18.8505002447346 51.0551785667194 + + + + + + + gml:Point + gml:LineString + gml:Polygon + gml:Envelope + + + + + + + + + + + + + + + + + + + LessThan + GreaterThan + LessThanEqualTo + GreaterThanEqualTo + EqualTo + NotEqualTo + Like + Between + + + + + + + + diff --git a/tests/resources/wfs_empty_other_srs_GetCapabilities_2_0_0.xml b/tests/resources/wfs_empty_other_srs_GetCapabilities_2_0_0.xml new file mode 100644 index 00000000..5271ad23 --- /dev/null +++ b/tests/resources/wfs_empty_other_srs_GetCapabilities_2_0_0.xml @@ -0,0 +1,228 @@ + + + + CZE INSPIRE Download Service - Cadastral Parcels + Cadastral Parcels - INSPIRE themes + OGC WFS + 2.0.0 + + + Czech Office for Surveying, Mapping and Cadastre + + + + + +420284041550 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2.2.0 + + + + + TRUE + + + + FALSE + + + + FALSE + + + + TRUE + + + + TRUE + + + + TRUE + + + + FALSE + + + + FALSE + + + + FALSE + + + + FALSE + + + + FALSE + + + + FALSE + + + + FALSE + + + + FALSE + + + + + CP:CadastralBoundary + Cadastral Parcel Boundaries + Cadastral Parcel Boundaries + + Cadastral Parcel Boundaries + + urn:ogc:def:crs:EPSG::102067 + + + text/xml; subtype=gml/3.2.1 + + + 10 43 + 22 55 + + + + CP:CadastralParcel + Cadastral parcel polygons + Cadastral parcel polygons + + Cadastral parcel polygons + + urn:ogc:def:crs:EPSG::102067 + + + text/xml; subtype=gml/3.2.1 + + + 10 43 + 22 55 + + + + CP:CadastralZoning + Cadastral Zoning polygons + Cadastral Zoning polygons + + Cadastral Zoning polygons + + urn:ogc:def:crs:EPSG::102067 + + + text/xml; subtype=gml/3.2.1 + + + 10 43 + 22 55 + + + + + + + + TRUE + + + + TRUE + + + + FALSE + + + + TRUE + + + + TRUE + + + + TRUE + + + + FALSE + + + + FALSE + + + + FALSE + + + + FALSE + + + + TRUE + + + + FALSE + + + + diff --git a/tests/test_wfs_generic.py b/tests/test_wfs_generic.py index d2ccd193..052ae39e 100644 --- a/tests/test_wfs_generic.py +++ b/tests/test_wfs_generic.py @@ -1,3 +1,6 @@ +from itertools import chain +from operator import attrgetter + from owslib.feature.common import CapabilitiesError from owslib.wfs import WebFeatureService from owslib.util import ServiceException @@ -232,3 +235,15 @@ def test_xmlfilter_wfs_200(): response = wfs.getfeature(**getfeat_params).read() assert b'Boolgeeda Iron Formation' in response + + +def test_handles_empty_other_srs(): + with open(resource_file("wfs_empty_other_srs_GetCapabilities_1_1_0.xml"), "rb") as fio: + wfs = WebFeatureService('http://gis.bnhelp.cz/ows/crwfs', xml=fio.read(), version='1.1.0') + crs_options = chain.from_iterable(map(attrgetter('crsOptions'), wfs.contents.values())) + assert {"urn:ogc:def:crs:EPSG::4326"} == set(map(attrgetter("id"), crs_options)) + + with open(resource_file("wfs_empty_other_srs_GetCapabilities_2_0_0.xml"), "rb") as fio: + wfs = WebFeatureService('http://gis.bnhelp.cz/ows/crwfs', xml=fio.read(), version='2.0.0') + crs_options = chain.from_iterable(map(attrgetter('crsOptions'), wfs.contents.values())) + assert {"urn:ogc:def:crs:EPSG::102067"} == set(map(attrgetter("id"), crs_options)) \ No newline at end of file