From d0d5b58224c09daffb49d88cc292bec54daed479 Mon Sep 17 00:00:00 2001 From: Kai Volland Date: Mon, 12 May 2025 17:11:58 +0200 Subject: [PATCH 1/3] fix: update datatype determination for WFS attributes --- owslib/feature/schema.py | 42 ++++++++++++++++++++++++++-- tests/test_wfs_schema.py | 59 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/owslib/feature/schema.py b/owslib/feature/schema.py index 403642bf2..c862e1947 100644 --- a/owslib/feature/schema.py +++ b/owslib/feature/schema.py @@ -54,6 +54,7 @@ def get_schema( type_element = root.find("./{%s}element" % XS_NAMESPACE) if type_element is None: return None + complex_type = type_element.attrib["type"].split(":")[1] elements = _get_elements(complex_type, root) nsmap = None @@ -78,16 +79,45 @@ def _get_elements(complex_type, root): return found_elements +def _get_datatype(element, schema_key, gml_key): + """Extract the data type from an element based on different XML structure variants. + + :param element: The XML element to extract the data type from + :param str schema_key: The XML namespace key for schema elements + :param str gml_key: The XML namespace key for GML elements + :return: The extracted data type as string + """ + # Case 1: Type defined as attribute + if "type" in element.attrib: + data_type = element.attrib["type"] + # Remove any namespace prefix + if ":" in data_type: + data_type = data_type.split(":")[-1] + return data_type + # Case 2: Reference to another element + elif "ref" in element.attrib: + return element.attrib["ref"].split(":")[-1] + # Case 3: Type defined as SimpleType with Restriction + simple_type = element.find(".//{%s}restriction" % XS_NAMESPACE) + if simple_type is not None: + return simple_type.attrib.get("base", "").replace(schema_key + ":", "") + # Case 4: Complex Type Definition + complex_type = element.find(".//{%s}complexType//{%s}element" % (XS_NAMESPACE, XS_NAMESPACE)) + if complex_type is not None and "type" in complex_type.attrib: + return complex_type.attrib["type"].replace(schema_key + ":", "") + return None + + def _construct_schema(elements, nsmap): - """Consruct fiona schema based on given elements + """Construct fiona schema based on given elements :param list Element: list of elements :param dict nsmap: namespace map - :return dict: schema """ if elements is None: return None + schema = {"properties": {}, "required": [], "geometry": None} schema_key = None @@ -123,10 +153,16 @@ def _construct_schema(elements, nsmap): } for element in elements: - data_type = element.attrib["type"].replace(gml_key + ":", "") + if "name" not in element.attrib: + continue + name = element.attrib["name"] non_nillable = element.attrib.get("nillable", "false") == "false" + data_type = _get_datatype(element, schema_key, gml_key) + if data_type is None: + continue + if data_type in mappings: schema["geometry"] = mappings[data_type] schema["geometry_column"] = name diff --git a/tests/test_wfs_schema.py b/tests/test_wfs_schema.py index a6c9feefc..d47be58b9 100644 --- a/tests/test_wfs_schema.py +++ b/tests/test_wfs_schema.py @@ -173,3 +173,62 @@ def test_get_schema_typename_eq_attribute( """ wfs110 = WebFeatureService(WFS_SERVICE_URL, version='1.1.0') schema = wfs110.get_schema('gw_varia:hhz') + + def test_get_datatype(self): + """Test the _get_datatype helper function with different XML structures.""" + from owslib.feature.schema import _get_datatype, XS_NAMESPACE + from owslib.etree import etree + + ns = { + 'xs': XS_NAMESPACE, + 'gml': 'http://www.opengis.net/gml', + 'xsd': 'http://www.w3.org/2001/XMLSchema' + } + + # Case 1: Type defined as attribute + # XML: + element1 = etree.Element('{%s}element' % XS_NAMESPACE, + attrib={'name': 'field1', 'type': 'gml:PointPropertyType'}, + nsmap=ns) + assert _get_datatype(element1, "xsd", "gml") == "PointPropertyType" + + # Case 2: Reference to another element + # XML: + element2 = etree.Element('{%s}element' % XS_NAMESPACE, + attrib={'name': 'field2', 'ref': 'gml:polygonProperty'}, + nsmap=ns) + assert _get_datatype(element2, "xsd", "gml") == "polygonProperty" + + # Case 3: SimpleType with Restriction + # XML: + # + # + # + # + # + element3 = etree.Element('{%s}element' % XS_NAMESPACE, attrib={'name': 'field3'}, nsmap=ns) + simple_type = etree.SubElement(element3, '{%s}simpleType' % XS_NAMESPACE) + restriction = etree.SubElement(simple_type, '{%s}restriction' % XS_NAMESPACE, + attrib={'base': 'xsd:string'}) + assert _get_datatype(element3, "xsd", "gml") == "string" + + # Case 4: Complex Type Definition + # XML: + # + # + # + # + # + # + # + element4 = etree.Element('{%s}element' % XS_NAMESPACE, attrib={'name': 'field4'}, nsmap=ns) + complex_type = etree.SubElement(element4, '{%s}complexType' % XS_NAMESPACE) + sequence = etree.SubElement(complex_type, '{%s}sequence' % XS_NAMESPACE) + sub_element = etree.SubElement(sequence, '{%s}element' % XS_NAMESPACE, + attrib={'type': 'xsd:string'}) + assert _get_datatype(element4, "xsd", "gml") == "string" + + # Case 5: Unknown structure + # XML: + element5 = etree.Element('{%s}element' % XS_NAMESPACE, attrib={'name': 'field5'}, nsmap=ns) + assert _get_datatype(element5, "xsd", "gml") is None From c44f7b8ced9d3cb4115f4255f678875070c0b717 Mon Sep 17 00:00:00 2001 From: Kai Volland Date: Mon, 12 May 2025 17:12:32 +0200 Subject: [PATCH 2/3] fix: update service_ok util to support arcgis server --- ...s_koeln_arcgis_describefeaturetype_110.xml | 177 +++ ...s_koeln_arcgis_describefeaturetype_200.xml | 177 +++ .../wfs_koeln_arcgis_getcapabilities_110.xml | 1256 +++++++++++++++++ .../wfs_koeln_arcgis_getcapabilities_200.xml | 1022 ++++++++++++++ tests/test_wfs_schema_arcgis_server.py | 154 ++ tests/utils.py | 9 +- 6 files changed, 2791 insertions(+), 4 deletions(-) create mode 100644 tests/resources/wfs_koeln_arcgis_describefeaturetype_110.xml create mode 100644 tests/resources/wfs_koeln_arcgis_describefeaturetype_200.xml create mode 100644 tests/resources/wfs_koeln_arcgis_getcapabilities_110.xml create mode 100644 tests/resources/wfs_koeln_arcgis_getcapabilities_200.xml create mode 100644 tests/test_wfs_schema_arcgis_server.py diff --git a/tests/resources/wfs_koeln_arcgis_describefeaturetype_110.xml b/tests/resources/wfs_koeln_arcgis_describefeaturetype_110.xml new file mode 100644 index 000000000..11046540b --- /dev/null +++ b/tests/resources/wfs_koeln_arcgis_describefeaturetype_110.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/resources/wfs_koeln_arcgis_describefeaturetype_200.xml b/tests/resources/wfs_koeln_arcgis_describefeaturetype_200.xml new file mode 100644 index 000000000..55b6ac5ae --- /dev/null +++ b/tests/resources/wfs_koeln_arcgis_describefeaturetype_200.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/resources/wfs_koeln_arcgis_getcapabilities_110.xml b/tests/resources/wfs_koeln_arcgis_getcapabilities_110.xml new file mode 100644 index 000000000..44bd0450d --- /dev/null +++ b/tests/resources/wfs_koeln_arcgis_getcapabilities_110.xml @@ -0,0 +1,1256 @@ + + + + Adressen je Stadtteil + + + ESRI(LongLat) + + WFS + 1.1.0 + + + + + Stadt Köln - Amt für Stadtentwicklung und Statistik + + Raumbezugssystem + + + + + + + + Willy-Brandt-Platz 2 + Köln + + 50679 + Deutschland + statistik-rbs@stadt-koeln.de + + + + + + + + + + + + + + + + + + 1.1.0 + + + GML3 + text/xml; subtype=gml/3.1.1 + + + + + + + + + + + GML3 + text/xml; subtype=gml/3.1.1 + + + + + + + + + + + results + hits + + + GML3 + text/xml; subtype=gml/3.1.1 + + + + + + Query + + + adressen_stadtteil:Altstadt_Nord + Altstadt_Nord + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Altstadt_Süd + Altstadt_Süd + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Bayenthal + Bayenthal + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Bickendorf + Bickendorf + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Bilderstöckchen + Bilderstöckchen + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Blumenberg + Blumenberg + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Bocklemünd_Mengenich + Bocklemünd_Mengenich + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Braunsfeld + Braunsfeld + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Brück + Brück + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Buchforst + Buchforst + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Buchheim + Buchheim + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Chorweiler + Chorweiler + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Dellbrück + Dellbrück + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Deutz + Deutz + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Dünnwald + Dünnwald + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Ehrenfeld + Ehrenfeld + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Eil + Eil + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Elsdorf + Elsdorf + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Ensen + Ensen + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Esch_Auweiler + Esch_Auweiler + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Finkenberg + Finkenberg + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Flittard + Flittard + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Fühlingen + Fühlingen + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Godorf + Godorf + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Gremberghoven + Gremberghoven + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Grengel + Grengel + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Hahnwald + Hahnwald + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Heimersdorf + Heimersdorf + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Höhenberg + Höhenberg + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Höhenhaus + Höhenhaus + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Holweide + Holweide + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Humboldt_Gremberg + Humboldt_Gremberg + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Immendorf + Immendorf + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Junkersdorf + Junkersdorf + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Kalk + Kalk + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Klettenberg + Klettenberg + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Langel + Langel + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Libur + Libur + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Lind + Lind + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Lindenthal + Lindenthal + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Lindweiler + Lindweiler + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Longerich + Longerich + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Lövenich + Lövenich + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Marienburg + Marienburg + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Mauenheim + Mauenheim + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Merheim + Merheim + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Merkenich + Merkenich + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Meschenich + Meschenich + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Mülheim + Mülheim + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Müngersdorf + Müngersdorf + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Neubrück + Neubrück + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Neuehrenfeld + Neuehrenfeld + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Neustadt_Nord + Neustadt_Nord + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Neustadt_Süd + Neustadt_Süd + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Niehl + Niehl + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Nippes + Nippes + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Ossendorf + Ossendorf + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Ostheim + Ostheim + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Pesch + Pesch + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Poll + Poll + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Porz + Porz + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Raderberg + Raderberg + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Raderthal + Raderthal + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Rath_Heumar + Rath_Heumar + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Riehl + Riehl + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Rodenkirchen + Rodenkirchen + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Roggendorf_Thenhoven + Roggendorf_Thenhoven + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Rondorf + Rondorf + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Seeberg + Seeberg + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Stammheim + Stammheim + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Sülz + Sülz + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Sürth + Sürth + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Urbach + Urbach + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Vingst + Vingst + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Vogelsang + Vogelsang + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Volkhoven_Weiler + Volkhoven_Weiler + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Wahn + Wahn + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Wahnheide + Wahnheide + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Weiden + Weiden + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Weidenpesch + Weidenpesch + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Weiß + Weiß + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Westhoven + Westhoven + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Widdersdorf + Widdersdorf + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Worringen + Worringen + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Zollstock + Zollstock + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Zündorf + Zündorf + urn:ogc:def:crs:EPSG::25832 + + GML3 + text/xml; subtype=gml/3.1.1 + + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + + + + gml:Envelope + gml:Point + gml:Polygon + gml:LineString + + + + + + + + + + + + + + + + + EqualTo + NotEqualTo + LessThan + GreaterThan + LessThanEqualTo + GreaterThanEqualTo + Like + Between + NullCheck + + + + + + + + diff --git a/tests/resources/wfs_koeln_arcgis_getcapabilities_200.xml b/tests/resources/wfs_koeln_arcgis_getcapabilities_200.xml new file mode 100644 index 000000000..820822cfe --- /dev/null +++ b/tests/resources/wfs_koeln_arcgis_getcapabilities_200.xml @@ -0,0 +1,1022 @@ + + + + WFS + + + ESRI(LongLat) + + WFS + 2.0.0 + + + + + Stadt Köln - Amt für Stadtentwicklung und Statistik + + Raumbezugssystem + + + + + + + + Willy-Brandt-Platz 2 + Köln + + 50679 + Deutschland + statistik-rbs@stadt-koeln.de + + + + + + + + + + + + + + + + + + + 1.0.0 + 1.1.0 + 2.0.0 + + + + + + + + + + + + + text/xml; subtype=gml/3.2 + + + + + + + + + + + + + none + local + + + + + + + + + + + + + results + hits + + + + + GML32 + GML32+ZIP + GML32+GZIP + application/gml+xml; version=3.2 + GML3 + GML3+ZIP + GML3+GZIP + text/xml; subtype=gml/3.1.1 + GML2 + GML2+ZIP + GML2+GZIP + text/xml; subtype=gml/2.1.2 + GEOJSON + GEOJSON+ZIP + GEOJSON+GZIP + ESRIGEOJSON + ESRIGEOJSON+ZIP + ESRIGEOJSON+GZIP + KML + application/vnd.google-earth.kml xml + application/vnd.google-earth.kml+xml + KMZ + application/vnd.google-earth.kmz + SHAPE+ZIP + CSV + CSV+ZIP + CSV+GZIP + Geopackage + Geopackage+ZIP + + + + + none + local + + + + + + + + + + + + + + + + + + + + + + + + + + + + TRUE + FALSE + FALSE + TRUE + TRUE + FALSE + FALSE + FALSE + TRUE + FALSE + FALSE + FALSE + FALSE + FALSE + + + + adressen_stadtteil:Altstadt_Nord + Altstadt_Nord + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Altstadt_Süd + Altstadt_Süd + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Bayenthal + Bayenthal + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Bickendorf + Bickendorf + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Bilderstöckchen + Bilderstöckchen + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Blumenberg + Blumenberg + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Bocklemünd_Mengenich + Bocklemünd_Mengenich + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Braunsfeld + Braunsfeld + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Brück + Brück + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Buchforst + Buchforst + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Buchheim + Buchheim + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Chorweiler + Chorweiler + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Dellbrück + Dellbrück + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Deutz + Deutz + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Dünnwald + Dünnwald + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Ehrenfeld + Ehrenfeld + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Eil + Eil + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Elsdorf + Elsdorf + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Ensen + Ensen + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Esch_Auweiler + Esch_Auweiler + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Finkenberg + Finkenberg + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Flittard + Flittard + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Fühlingen + Fühlingen + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Godorf + Godorf + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Gremberghoven + Gremberghoven + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Grengel + Grengel + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Hahnwald + Hahnwald + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Heimersdorf + Heimersdorf + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Höhenberg + Höhenberg + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Höhenhaus + Höhenhaus + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Holweide + Holweide + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Humboldt_Gremberg + Humboldt_Gremberg + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Immendorf + Immendorf + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Junkersdorf + Junkersdorf + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Kalk + Kalk + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Klettenberg + Klettenberg + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Langel + Langel + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Libur + Libur + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Lind + Lind + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Lindenthal + Lindenthal + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Lindweiler + Lindweiler + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Longerich + Longerich + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Lövenich + Lövenich + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Marienburg + Marienburg + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Mauenheim + Mauenheim + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Merheim + Merheim + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Merkenich + Merkenich + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Meschenich + Meschenich + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Mülheim + Mülheim + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Müngersdorf + Müngersdorf + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Neubrück + Neubrück + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Neuehrenfeld + Neuehrenfeld + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Neustadt_Nord + Neustadt_Nord + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Neustadt_Süd + Neustadt_Süd + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Niehl + Niehl + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Nippes + Nippes + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Ossendorf + Ossendorf + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Ostheim + Ostheim + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Pesch + Pesch + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Poll + Poll + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Porz + Porz + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Raderberg + Raderberg + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Raderthal + Raderthal + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Rath_Heumar + Rath_Heumar + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Riehl + Riehl + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Rodenkirchen + Rodenkirchen + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Roggendorf_Thenhoven + Roggendorf_Thenhoven + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Rondorf + Rondorf + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Seeberg + Seeberg + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Stammheim + Stammheim + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Sülz + Sülz + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Sürth + Sürth + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Urbach + Urbach + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Vingst + Vingst + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Vogelsang + Vogelsang + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Volkhoven_Weiler + Volkhoven_Weiler + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Wahn + Wahn + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Wahnheide + Wahnheide + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Weiden + Weiden + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Weidenpesch + Weidenpesch + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Weiß + Weiß + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Westhoven + Westhoven + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Widdersdorf + Widdersdorf + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Worringen + Worringen + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Zollstock + Zollstock + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + adressen_stadtteil:Zündorf + Zündorf + urn:ogc:def:crs:EPSG::25832 + + 6.80534263 50.83164204 + 7.13337013 51.08846294 + + + + + + TRUE + TRUE + TRUE + TRUE + TRUE + TRUE + TRUE + TRUE + FALSE + FALSE + FALSE + TRUE + FALSE + TRUE + FALSE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_wfs_schema_arcgis_server.py b/tests/test_wfs_schema_arcgis_server.py new file mode 100644 index 000000000..be75c7683 --- /dev/null +++ b/tests/test_wfs_schema_arcgis_server.py @@ -0,0 +1,154 @@ +import pytest + +import owslib +from owslib.etree import etree +from owslib.wfs import WebFeatureService +from tests.utils import service_ok + +WFS_SERVICE_URL = 'https://geoportal.stadt-koeln.de/arcgis/services/basiskarten/adressen_stadtteil/MapServer/WFSServer?SERVICE=WFS&request=GetCapabilities' + + +@pytest.fixture +def mp_wfs_110(monkeypatch): + """Monkeypatch the call to the remote GetCapabilities request of WFS + version 1.1.0. + + Parameters + ---------- + monkeypatch : pytest.fixture + PyTest monkeypatch fixture. + """ + def read(*args, **kwargs): + with open('tests/resources/wfs_koeln_arcgis_getcapabilities_110.xml', 'r') as f: + data = f.read() + if type(data) is not bytes: + data = data.encode('utf-8') + data = etree.fromstring(data) + return data + + monkeypatch.setattr( + owslib.feature.common.WFSCapabilitiesReader, 'read', read) + + +@pytest.fixture +def mp_wfs_200(monkeypatch): + """Monkeypatch the call to the remote GetCapabilities request of WFS + version 2.0.0. + + Parameters + ---------- + monkeypatch : pytest.fixture + PyTest monkeypatch fixture. + """ + def read(*args, **kwargs): + with open('tests/resources/wfs_koeln_arcgis_getcapabilities_200.xml', 'r') as f: + data = f.read() + if type(data) is not bytes: + data = data.encode('utf-8') + data = etree.fromstring(data) + return data + + monkeypatch.setattr( + owslib.feature.common.WFSCapabilitiesReader, 'read', read) + + +@pytest.fixture() +def mp_remote_describefeaturetype(monkeypatch): + """Monkeypatch the call to the remote DescribeFeatureType request. + + Returns a standard DescribeFeatureType response. + + Parameters + ---------- + monkeypatch : pytest.fixture + PyTest monkeypatch fixture. + """ + def __remote_describefeaturetype(*args, **kwargs): + with open('tests/resources/wfs_koeln_arcgis_describefeaturetype_110.xml', 'r') as f: + data = f.read() + if type(data) is not bytes: + data = data.encode('utf-8') + data = etree.fromstring(data) + return data + + monkeypatch.setattr(owslib.feature.schema, + '_get_remote_describefeaturetype', + __remote_describefeaturetype) + + +class TestOnline(object): + """Class grouping online tests for the WFS get_schema method.""" + + @pytest.mark.xfail + @pytest.mark.online + @pytest.mark.skipif(not service_ok(WFS_SERVICE_URL), + reason="WFS service is unreachable") + @pytest.mark.parametrize("wfs_version", ["1.1.0", "2.0.0"]) + def test_get_schema(self, wfs_version): + """Test the get_schema method for a standard schema.""" + wfs = WebFeatureService(WFS_SERVICE_URL, version=wfs_version) + schema = wfs.get_schema('adressen_stadtteil:Blumenberg') + + @pytest.mark.xfail + @pytest.mark.online + @pytest.mark.skipif(not service_ok(WFS_SERVICE_URL), + reason="WFS service is unreachable") + @pytest.mark.parametrize("wfs_version", ["1.1.0", "2.0.0"]) + def test_schema_result(self, wfs_version): + """Test whether the output from get_schema is a wellformed dictionary.""" + wfs = WebFeatureService(WFS_SERVICE_URL, version=wfs_version) + schema = wfs.get_schema('adressen_stadtteil:Blumenberg') + assert isinstance(schema, dict) + + assert 'properties' in schema or 'geometry' in schema + + if 'geometry' in schema: + assert 'geometry_column' in schema + + if 'properties' in schema: + assert isinstance(schema['properties'], dict) + + assert 'required' in schema + assert isinstance(schema['required'], list) + + +class TestOffline(object): + """Class grouping offline tests for the WFS get_schema method.""" + + def test_get_schema(self, mp_wfs_110, mp_remote_describefeaturetype): + """Test the get_schema method for a standard schema. + + Parameters + ---------- + mp_wfs_110 : pytest.fixture + Monkeypatch the call to the remote GetCapabilities request. + mp_remote_describefeaturetype : pytest.fixture + Monkeypatch the call to the remote DescribeFeatureType request. + """ + wfs = WebFeatureService(WFS_SERVICE_URL, version='1.1.0') + schema = wfs.get_schema('adressen_stadtteil:Blumenberg') + + def test_schema_result(self, mp_wfs_110, mp_remote_describefeaturetype): + """Test whether the output from get_schema is a wellformed dictionary. + + Parameters + ---------- + mp_wfs_110 : pytest.fixture + Monkeypatch the call to the remote GetCapabilities request. + mp_remote_describefeaturetype : pytest.fixture + Monkeypatch the call to the remote DescribeFeatureType request. + """ + wfs = WebFeatureService(WFS_SERVICE_URL, version='1.1.0') + schema = wfs.get_schema('adressen_stadtteil:Blumenberg') + assert isinstance(schema, dict) + + assert 'properties' in schema or 'geometry' in schema + + if 'geometry' in schema: + assert 'geometry_column' in schema + + if 'properties' in schema: + assert isinstance(schema['properties'], dict) + + assert 'required' in schema + assert isinstance(schema['required'], list) diff --git a/tests/utils.py b/tests/utils.py index 56de52057..e52cf8388 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -83,12 +83,13 @@ def sorted_url_query(url): def service_ok(url, timeout=5): try: - resp = requests.head(url, allow_redirects=True, timeout=timeout) + resp = requests.get(url, allow_redirects=True, timeout=timeout, stream=True) if 'html' in resp.headers.get('content-type', '').lower(): + resp.close() return False - if not resp.ok: # if HEAD is not supported try GET with streaming - resp = requests.get(url, timeout=timeout, stream=True) - return resp.ok + ok = resp.ok + resp.close() + return ok except requests.exceptions.ReadTimeout: ok = False except requests.exceptions.ConnectTimeout: From efa6c201b6cf2b33e281b9887b6594cefcaf3cee Mon Sep 17 00:00:00 2001 From: Kai Volland Date: Tue, 13 May 2025 10:08:34 +0200 Subject: [PATCH 3/3] test: parametrize data_type tests --- tests/test_wfs_schema.py | 172 +++++++++++++++++++++++++++++++++------ 1 file changed, 145 insertions(+), 27 deletions(-) diff --git a/tests/test_wfs_schema.py b/tests/test_wfs_schema.py index d47be58b9..e0ccfd5de 100644 --- a/tests/test_wfs_schema.py +++ b/tests/test_wfs_schema.py @@ -82,6 +82,9 @@ def __remote_describefeaturetype(*args, **kwargs): __remote_describefeaturetype) + + + class TestOnline(object): """Class grouping online tests for the WFS get_schema method.""" @pytest.mark.xfail @@ -174,8 +177,8 @@ def test_get_schema_typename_eq_attribute( wfs110 = WebFeatureService(WFS_SERVICE_URL, version='1.1.0') schema = wfs110.get_schema('gw_varia:hhz') - def test_get_datatype(self): - """Test the _get_datatype helper function with different XML structures.""" + def test_get_datatype_geometry(self): + """Test the _get_datatype helper function with geometry types.""" from owslib.feature.schema import _get_datatype, XS_NAMESPACE from owslib.etree import etree @@ -185,50 +188,165 @@ def test_get_datatype(self): 'xsd': 'http://www.w3.org/2001/XMLSchema' } - # Case 1: Type defined as attribute + # Test geometry type # XML: - element1 = etree.Element('{%s}element' % XS_NAMESPACE, - attrib={'name': 'field1', 'type': 'gml:PointPropertyType'}, - nsmap=ns) - assert _get_datatype(element1, "xsd", "gml") == "PointPropertyType" + element = etree.Element('{%s}element' % XS_NAMESPACE, + attrib={'name': 'field1', 'type': 'gml:PointPropertyType'}, + nsmap=ns) + assert _get_datatype(element, "xsd", "gml") == "PointPropertyType" + + def test_get_datatype_reference(self): + """Test the _get_datatype helper function with element references.""" + from owslib.feature.schema import _get_datatype, XS_NAMESPACE + from owslib.etree import etree - # Case 2: Reference to another element + ns = { + 'xs': XS_NAMESPACE, + 'gml': 'http://www.opengis.net/gml', + 'xsd': 'http://www.w3.org/2001/XMLSchema' + } + + # Test element reference # XML: - element2 = etree.Element('{%s}element' % XS_NAMESPACE, - attrib={'name': 'field2', 'ref': 'gml:polygonProperty'}, - nsmap=ns) - assert _get_datatype(element2, "xsd", "gml") == "polygonProperty" + element = etree.Element('{%s}element' % XS_NAMESPACE, + attrib={'name': 'field2', 'ref': 'gml:polygonProperty'}, + nsmap=ns) + assert _get_datatype(element, "xsd", "gml") == "polygonProperty" + + @pytest.mark.parametrize("data_type", [ + "xsd:boolean", + "xsd:date", + "xsd:dateTime", + "xsd:double", + "xsd:float", + "xsd:integer", + "xsd:int", + "xsd:string", + ]) + def test_get_datatype_simple_types(self, data_type): + """Test the _get_datatype helper function with different simple types. + + Parameters + ---------- + data_type : str + The XML Schema data type to test + """ + from owslib.feature.schema import _get_datatype, XS_NAMESPACE + from owslib.etree import etree - # Case 3: SimpleType with Restriction + ns = { + 'xs': XS_NAMESPACE, + 'gml': 'http://www.opengis.net/gml', + 'xsd': 'http://www.w3.org/2001/XMLSchema' + } + + # Test simple type with restriction # XML: # # - # + # # # - element3 = etree.Element('{%s}element' % XS_NAMESPACE, attrib={'name': 'field3'}, nsmap=ns) - simple_type = etree.SubElement(element3, '{%s}simpleType' % XS_NAMESPACE) + element = etree.Element('{%s}element' % XS_NAMESPACE, attrib={'name': 'field3'}, nsmap=ns) + simple_type = etree.SubElement(element, '{%s}simpleType' % XS_NAMESPACE) restriction = etree.SubElement(simple_type, '{%s}restriction' % XS_NAMESPACE, - attrib={'base': 'xsd:string'}) - assert _get_datatype(element3, "xsd", "gml") == "string" + attrib={'base': data_type}) + expected_type = data_type.split(":")[-1] + assert _get_datatype(element, "xsd", "gml") == expected_type + + @pytest.mark.parametrize("data_type", [ + "xsd:boolean", + "xsd:date", + "xsd:dateTime", + "xsd:double", + "xsd:float", + "xsd:integer", + "xsd:int", + "xsd:string", + ]) + def test_get_datatype_direct_types(self, data_type): + """Test the _get_datatype helper function with direct type attributes. + + Parameters + ---------- + data_type : str + The XML Schema data type to test + """ + from owslib.feature.schema import _get_datatype, XS_NAMESPACE + from owslib.etree import etree - # Case 4: Complex Type Definition + ns = { + 'xs': XS_NAMESPACE, + 'gml': 'http://www.opengis.net/gml', + 'xsd': 'http://www.w3.org/2001/XMLSchema' + } + + # Test direct type attribute + # XML: + element = etree.Element('{%s}element' % XS_NAMESPACE, + attrib={'name': 'field1', 'type': data_type}, + nsmap=ns) + expected_type = data_type.split(":")[-1] + assert _get_datatype(element, "xsd", "gml") == expected_type + + @pytest.mark.parametrize("data_type", [ + "xsd:boolean", + "xsd:date", + "xsd:dateTime", + "xsd:double", + "xsd:float", + "xsd:integer", + "xsd:int", + "xsd:string", + ]) + def test_get_datatype_complex_types(self, data_type): + """Test the _get_datatype helper function with complex type definitions. + + Parameters + ---------- + data_type : str + The XML Schema data type to test + """ + from owslib.feature.schema import _get_datatype, XS_NAMESPACE + from owslib.etree import etree + + ns = { + 'xs': XS_NAMESPACE, + 'gml': 'http://www.opengis.net/gml', + 'xsd': 'http://www.w3.org/2001/XMLSchema' + } + + # Test complex type # XML: # # # - # + # # # # - element4 = etree.Element('{%s}element' % XS_NAMESPACE, attrib={'name': 'field4'}, nsmap=ns) - complex_type = etree.SubElement(element4, '{%s}complexType' % XS_NAMESPACE) + element = etree.Element('{%s}element' % XS_NAMESPACE, attrib={'name': 'field4'}, nsmap=ns) + complex_type = etree.SubElement(element, '{%s}complexType' % XS_NAMESPACE) sequence = etree.SubElement(complex_type, '{%s}sequence' % XS_NAMESPACE) sub_element = etree.SubElement(sequence, '{%s}element' % XS_NAMESPACE, - attrib={'type': 'xsd:string'}) - assert _get_datatype(element4, "xsd", "gml") == "string" + attrib={'type': data_type}) + expected_type = data_type.split(":")[-1] + assert _get_datatype(element, "xsd", "gml") == expected_type + + + + def test_get_datatype_unknown(self): + """Test the _get_datatype helper function with unknown structure.""" + from owslib.feature.schema import _get_datatype, XS_NAMESPACE + from owslib.etree import etree + + ns = { + 'xs': XS_NAMESPACE, + 'gml': 'http://www.opengis.net/gml', + 'xsd': 'http://www.w3.org/2001/XMLSchema' + } - # Case 5: Unknown structure + # Test unknown structure # XML: - element5 = etree.Element('{%s}element' % XS_NAMESPACE, attrib={'name': 'field5'}, nsmap=ns) - assert _get_datatype(element5, "xsd", "gml") is None + element = etree.Element('{%s}element' % XS_NAMESPACE, attrib={'name': 'field5'}, nsmap=ns) + assert _get_datatype(element, "xsd", "gml") is None