Пример #1
0
    def parse_style(self, layer, layer_obj):
        style_xml = xml_helper.try_get_single_element_from_xml(
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("Style"), layer)

        if style_xml is None:
            # no <Style> element found
            return

        style_obj = Style()

        style_obj.name = xml_helper.try_get_text_from_xml_element(
            style_xml, "./" + GENERIC_NAMESPACE_TEMPLATE.format("Name"))
        style_obj.title = xml_helper.try_get_text_from_xml_element(
            style_xml, "./" + GENERIC_NAMESPACE_TEMPLATE.format("Title"))
        legend_elem = xml_helper.try_get_single_element_from_xml(
            elem="./" + GENERIC_NAMESPACE_TEMPLATE.format("LegendURL") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("OnlineResource"),
            xml_elem=style_xml)
        style_obj.legend_uri = xml_helper.get_href_attribute(legend_elem)
        style_obj.width = int(
            xml_helper.try_get_attribute_from_xml_element(
                style_xml, "width",
                "./" + GENERIC_NAMESPACE_TEMPLATE.format("LegendURL")) or 0)
        style_obj.height = int(
            xml_helper.try_get_attribute_from_xml_element(
                style_xml, "height",
                "./" + GENERIC_NAMESPACE_TEMPLATE.format("LegendURL")) or 0)
        style_obj.mime_type = MimeType.objects.filter(
            mime_type=xml_helper.try_get_text_from_xml_element(
                style_xml, "./" +
                GENERIC_NAMESPACE_TEMPLATE.format("LegendURL") + "/ " +
                GENERIC_NAMESPACE_TEMPLATE.format("Format"))).first()

        layer_obj.style = style_obj
Пример #2
0
    def _parse_xml_legal_reports(self, xml_obj: Element):
        """ Parses existing CI_Date elements from the MD_DataIdentification element

        Args:
            xml_obj (Element): The document xml element
        Returns:

        """
        data_quality_elem = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("DQ_DataQuality"),
            xml_obj)
        report_elems = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("report"), xml_obj)
        for report_elem in report_elems:
            report = LegalReport()
            report.title = xml_helper.try_get_text_from_xml_element(
                report_elem,
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("title") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("CharacterString"))
            report.explanation = xml_helper.try_get_text_from_xml_element(
                report_elem,
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("explanation") +
                "/" + GENERIC_NAMESPACE_TEMPLATE.format("CharacterString"))
            legal_date = LegalDate()
            legal_date.date = xml_helper.try_get_text_from_xml_element(
                report_elem, ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Date"))
            legal_date.date_type_code = xml_helper.try_get_attribute_from_xml_element(
                report_elem, "codeListValue",
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("CI_DateTypeCode"))
            legal_date.date_type_code_list_url = xml_helper.try_get_attribute_from_xml_element(
                report_elem, "codeList",
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("CI_DateTypeCode"))
            report.date = legal_date
            self.legal_reports.append(report)
Пример #3
0
    def _parse_operations_metadata(self, upper_elem):
        """ Parses the <Operation> elements inside of <OperationsMetadata>

        Args:
            upper_elem (Element): The upper xml element
        Returns:

        """
        operations_objs = xml_helper.try_get_element_from_xml(
            ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Operation"),
            upper_elem
        )

        attribute_map = {
            OGCOperationEnum.GET_CAPABILITIES.value: 'get_capabilities_uri',
            OGCOperationEnum.DESCRIBE_RECORD.value: 'describe_record_uri',
            OGCOperationEnum.GET_RECORDS.value: 'get_records_uri',
            OGCOperationEnum.GET_RECORD_BY_ID.value: 'get_record_by_id_uri',
        }

        for operation in operations_objs:
            operation_name = xml_helper.try_get_attribute_from_xml_element(
                operation,
                "name",
            )
            get_uri = xml_helper.try_get_single_element_from_xml(
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Get"),
                operation
            )
            get_uri = xml_helper.get_href_attribute(get_uri) if get_uri is not None else None

            post_uri = xml_helper.try_get_single_element_from_xml(
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Post"),
                operation
            )
            post_uri = xml_helper.get_href_attribute(post_uri) if post_uri is not None else None

            if attribute_map.get(operation_name):
                setattr(self, attribute_map.get(operation_name)+'_GET', get_uri)
                setattr(self, attribute_map.get(operation_name)+'_POST', post_uri)
            else:
                # the given operation is not supported for now
                pass

            parameters = self._parse_parameter_metadata(operation)
            output_format = parameters.get("outputFormat", None)
            if output_format is not None:
                self.formats_list.append(
                    MimeType.objects.get_or_create(
                        operation=operation_name,
                        mime_type=output_format,
                    )[0]
                )
Пример #4
0
    def _get_axis_order(self, identifier: str):
        """ Returns the axis order for a given spatial result system

        Args:
            identifier:
        Returns:

        """
        id = self.get_real_identifier(identifier)

        axis_order = self.cacher.get(str(id))
        if axis_order is not None:
            axis_order = json.loads(axis_order)
            return axis_order

        XML_NAMESPACES["gml"] = "http://www.opengis.net/gml/3.2"

        uri = self.registry_uri + self.id_prefix + str(id)
        response = requests.request("Get", url=uri, proxies=PROXIES)
        response = xml_helper.parse_xml(str(response.content.decode()))
        type = xml_helper.try_get_text_from_xml_element(xml_elem=response,
                                                        elem="//epsg:type")
        if type == "projected":
            cartes_elem = xml_helper.try_get_single_element_from_xml(
                "//gml:cartesianCS", response)
            second_level_srs_uri = xml_helper.get_href_attribute(
                xml_elem=cartes_elem)
        elif type == "geographic 2D":
            geogr_elem = xml_helper.try_get_single_element_from_xml(
                "//gml:ellipsoidalCS", response)
            second_level_srs_uri = xml_helper.get_href_attribute(
                xml_elem=geogr_elem)
        else:
            second_level_srs_uri = ""

        uri = self.registry_uri + second_level_srs_uri
        response = requests.request("Get", url=uri, proxies=PROXIES)
        response = xml_helper.parse_xml(str(response.content.decode()))
        axis = xml_helper.try_get_element_from_xml("//gml:axisDirection",
                                                   response)
        order = []
        for a in axis:
            order.append(a.text)
        order = {
            "first_axis": order[0],
            "second_axis": order[1],
        }

        # Write this to cache, so it can be used on another request!
        self.cacher.set(str(id), json.dumps(order))

        return order
Пример #5
0
    def _get_axis_order(self, identifier: str):
        """ Returns the axis order for a given spatial result system

        Args:
            identifier:
        Returns:

        """
        id = self.get_real_identifier(identifier)

        axis_order = self.cacher.get(str(id))
        if axis_order is not None:
            axis_order = json.loads(axis_order)
            return axis_order

        XML_NAMESPACES["gml"] = "http://www.opengis.net/gml/3.2"
        XML_NAMESPACES["epsg"] = "urn:x-ogp:spec:schema-xsd:EPSG:2.2:dataset"
        uri = self.registry_uri.replace("{CRS_IDENTIFIER}", str(id))
        # change header
        headers = {'Accept': 'application/xml'}
        response = requests.request("Get", url=uri, proxies=PROXIES, headers=headers)
        response = xml_helper.parse_xml(str(response.content.decode()))
        type = xml_helper.try_get_text_from_xml_element(xml_elem=response, elem="//epsg:type")
        if type == "projected":
            cartes_elem = xml_helper.try_get_single_element_from_xml("//gml:cartesianCS", response)
            second_level_srs_uri = xml_helper.get_href_attribute(xml_elem=cartes_elem)
        elif type in ["geographic 2D", "geographic 2d"]:
            geogr_elem = xml_helper.try_get_single_element_from_xml("//gml:ellipsoidalCS", response)
            second_level_srs_uri = xml_helper.get_href_attribute(xml_elem=geogr_elem)
        else:
            second_level_srs_uri = ""

        uri = second_level_srs_uri
        headers = {'Accept': 'application/xml'}
        response = requests.request("Get", url=uri, proxies=PROXIES, headers=headers)
        response = xml_helper.parse_xml(str(response.content.decode()))
        axis = xml_helper.try_get_element_from_xml("//gml:axisDirection", response)
        order = []
        for a in axis:
            order.append(a.text)
        order = {
            "first_axis": order[0],
            "second_axis": order[1],
        }

        # Write this to cache, so it can be used on another request!
        self.cacher.set(str(id), json.dumps(order))

        return order
Пример #6
0
    def test_exception_report(self):
        """ Test for checking if the ows:ExceptionReport is working fine or not.

        Test by requesting a wrong operation

        Returns:

        """
        get_records_param = {
            "service": "CSW",
            "version": "2.0.2",
            "request": "WRONG_OPERATION",
            "id": self.test_id,
            "elementsetname": "brief",
            "typenames": "gmd:MD_Metadata",
            "outputschema": "http://www.isotc211.org/2005/gmd",
        }

        response = self.client.get(reverse(CSW_PATH), data=get_records_param)
        status_code = response.status_code
        content = response.content
        content_xml = xml_helper.parse_xml(content)

        self.assertEqual(response.status_code, 200,
                         WRONG_STATUS_CODE_TEMPLATE.format(status_code))
        self.assertIsNotNone(content_xml, INVALID_XML_MSG)
        exception_report_elem = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("ExceptionReport"),
            content_xml)
        self.assertIsNotNone(exception_report_elem,
                             "No ows:ExceptionReport was generated!")
Пример #7
0
    def create_metadata_elem(self, returned_md: Metadata):
        """ Returns existing service/dataset metadata as xml elements

        Args:
            returned_md (Metadata): The processing metadata
        Returns:
             xml (Element): The xml element
        """
        if returned_md.is_dataset_metadata:
            doc = Document.objects.get(
                metadata=returned_md,
                document_type=DocumentEnum.METADATA.value,
            )
            xml = doc.content
        else:
            xml = returned_md.get_service_metadata_xml()

        xml = xml_helper.parse_xml(xml)
        xml = xml_helper.try_get_single_element_from_xml(
            xml_elem=xml,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("MD_Metadata"))

        # Reduce the amount of information returned based on the requested elementSetName parameter
        xml = self.reduce_information(xml)

        return xml
Пример #8
0
    def _parse_xml_legal_dates(self, xml_obj: Element):
        """ Parses existing CI_Date elements from the MD_DataIdentification element

        Args:
            xml_obj (Element): The document xml element
        Returns:

        """
        md_data_ident_elem = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("MD_DataIdentification"),
            xml_obj)
        legal_date_elems = xml_helper.try_get_element_from_xml(
            ".//" + GENERIC_NAMESPACE_TEMPLATE.format("CI_Date"),
            md_data_ident_elem)
        if legal_date_elems:
            for legal_date_elem in legal_date_elems:
                legal_date = LegalDate()
                legal_date.date = xml_helper.try_get_text_from_xml_element(
                    legal_date_elem,
                    ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Date"))
                legal_date.date_type_code = xml_helper.try_get_attribute_from_xml_element(
                    legal_date_elem, "codeListValue", ".//" +
                    GENERIC_NAMESPACE_TEMPLATE.format("CI_DateTypeCode"))
                legal_date.date_type_code_list_url = xml_helper.try_get_attribute_from_xml_element(
                    legal_date_elem, "codeList", ".//" +
                    GENERIC_NAMESPACE_TEMPLATE.format("CI_DateTypeCode"))
                self.legal_dates.append(legal_date)
Пример #9
0
def transform_constraint_to_cql(constraint: str, constraint_language: str):
    """ Transforms a xml filter style constraint into CQL style

    Args:
        constraint (str): The constraint parameter
        constraint_language (str): The constraintlanguage parameter
    Returns:
         constraint (str): The transfored constrained
    """
    if constraint_language.upper() != "FILTER":
        raise ValueError(
            "{} is no valid CSW conform value. Choices are `CQL_TEXT, FILTER`".
            format(constraint_language), "constraintlanguage")

    constraint_xml = xml_helper.parse_xml(constraint)
    if constraint_xml is None:
        raise ValueError(
            "Constraint value is no valid xml! Did you set the correct value for 'constraintlanguage'?",
            CONSTRAINT_LOCATOR)
    filter_elem = xml_helper.try_get_single_element_from_xml(
        "//" + GENERIC_NAMESPACE_TEMPLATE.format("Filter"),
        constraint_xml.getroot())
    new_constraint = _transform_constraint_to_cql_recursive(filter_elem)

    return new_constraint
Пример #10
0
    def get_service_operations_and_formats(self, xml_obj):
        """ Creates table records from <Capability><Request></Request></Capability contents

        Creates MimeType records

        Args:
            xml_obj: The xml document object
        Returns:

        """
        cap_request = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("Capability") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("Request"),
            xml_obj
        )
        operations = cap_request.getchildren()
        for operation in operations:
            RequestOperation.objects.get_or_create(
                operation_name=operation.tag,
            )
            # Parse formats
            formats = xml_helper.try_get_element_from_xml(
                "./" + GENERIC_NAMESPACE_TEMPLATE.format("Format"),
                operation
            )
            formats = [f.text for f in formats]
            self.operation_format_map[operation.tag] = formats
Пример #11
0
    def get_version_specific_metadata(self, xml_obj):
        service_xml = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("Service"),
            xml_obj
        )
        # Keywords
        # Keywords are not separated in single <Keyword> elements.
        # There is a single <Keywords> element, containing a continuous string, where keywords are space separated
        keywords = xml_helper.try_get_text_from_xml_element(
            service_xml,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("Keywords")
        )
        keywords = keywords.split(" ")
        tmp = []
        for kw in keywords:
            kw = kw.strip()
            if len(kw) != 0:
               tmp.append(kw)
        self.service_identification_keywords = tmp

        # Online Resource
        # The online resource is not found as an attribute of an element.
        # It is the text of the <OnlineResource> element
        online_resource = xml_helper.try_get_text_from_xml_element(
            service_xml,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("OnlineResource")
        )
        self.service_provider_onlineresource_linkage = online_resource
Пример #12
0
    def _create_formats_from_md_metadata(self, md_metadata: Element) -> list:
        """ Creates a list of MimeType objects from MD_Metadata element

        Args:
            md_metadata (Element): The xml element
        Returns:
             formats (list)
        """
        formats = []
        distribution_elem = xml_helper.try_get_single_element_from_xml(
            ".//" + GENERIC_NAMESPACE_TEMPLATE.format("distributionFormat"),
            md_metadata)
        if distribution_elem is None:
            return formats
        md_format_elems = xml_helper.try_get_element_from_xml(
            ".//" + GENERIC_NAMESPACE_TEMPLATE.format("MD_Format"),
            md_metadata)
        for md_format_elem in md_format_elems:
            name = xml_helper.try_get_text_from_xml_element(
                md_format_elem,
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("name") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("CharacterString"))
            if name is not None:
                formats.append(name)
        return formats
Пример #13
0
def _overwrite_capabilities_data(xml_obj: _Element, metadata: Metadata):
    """ Overwrites capabilities document data with changed data from editor based changes.

    Only capable of changing <Title>, <Abstract> and <AccessConstraints>

    Args:
        xml_obj (_Element): The document xml object
        metadata (Metadata): The metadata holding the data
    Returns:

    """
    # Create licence appendix for AccessConstraints and Fees
    licence = metadata.licence
    licence_appendix = ""
    if licence is not None:
        licence_appendix = "\n {} ({}), \n {}, \n {}".format(
            licence.name, licence.identifier, licence.description,
            licence.description_url)
    elements = {
        "Title":
        metadata.title,
        "Abstract":
        metadata.abstract,
        "AccessConstraints":
        "{}{}".format(metadata.access_constraints, licence_appendix),
        "Fees":
        "{}{}".format(metadata.fees, licence_appendix),
    }

    for key, val in elements.items():
        try:
            # Check if element exists to change it
            key_xml_obj = xml_helper.try_get_single_element_from_xml(
                "./" + GENERIC_NAMESPACE_TEMPLATE.format(key), xml_obj)
            if key_xml_obj is not None:
                # Element exists, we can change it easily
                xml_helper.write_text_to_element(
                    xml_obj, "./" + GENERIC_NAMESPACE_TEMPLATE.format(key),
                    val)
            else:
                # The element does not exist (happens in case of abstract sometimes)
                # First create, than change it
                xml_helper.create_subelement(
                    xml_obj,
                    key,
                )
                xml_helper.write_text_to_element(
                    xml_obj, "./" + GENERIC_NAMESPACE_TEMPLATE.format(key),
                    val)
        except AttributeError as e:
            # for not is_root this will fail in AccessConstraints querying
            pass
Пример #14
0
    def get_service_operations_and_formats(self, xml_obj):
        """ Parses

        Args:
            xml_obj (Element): The xml as parsable element
        Returns:

        """
        operation_obj = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("OperationsMetadata"),
            xml_obj)

        # Parse Operation metadata
        self._parse_operations_metadata(upper_elem=operation_obj)

        # Parse Service parameters
        self._parse_parameter_metadata(upper_elem=operation_obj)
Пример #15
0
    def test_new_service_check_describing_attributes(self):
        return
        """ Tests whether the describing attributes, such as title or abstract, are correct.

        Checks for the service.
        Checks for each layer.

        Returns:

        """
        service = self.service_wms
        layers = service.get_subelements()
        cap_xml = xml_helper.parse_xml(self.cap_doc_wms.content)

        xml_title = xml_helper.try_get_text_from_xml_element(
            cap_xml, "//Service/Title")
        xml_abstract = xml_helper.try_get_text_from_xml_element(
            cap_xml, "//Service/Abstract")

        self.assertEqual(service.metadata.title, xml_title)
        self.assertEqual(service.metadata.abstract, xml_abstract)

        # run for layers
        for layer in layers:
            xml_layer = xml_helper.try_get_single_element_from_xml(
                "//Name[text()='{}']/parent::Layer".format(layer.identifier),
                cap_xml)
            if xml_layer is None:
                # this might happen for layers which do not provide a unique identifier. We generate an identifier automatically in this case.
                # this generated identifier - of course - can not be found in the xml document.
                continue
            xml_title = xml_helper.try_get_text_from_xml_element(
                xml_layer, "./Title")
            xml_abstract = xml_helper.try_get_text_from_xml_element(
                xml_layer, "./Abstract")
            self.assertEqual(
                layer.metadata.title,
                xml_title,
                msg="Failed for layer with identifier '{}' and title '{}'".
                format(layer.identifier, layer.metadata.title))
            self.assertEqual(
                layer.metadata.abstract,
                xml_abstract,
                msg="Failed for layer with identifier '{}' and title '{}'".
                format(layer.identifier, layer.metadata.title))
Пример #16
0
 def parse_dimension(self, layer, layer_obj):
     dim_list = []
     try:
         dims = xml_helper.try_get_element_from_xml(
             elem="./" + GENERIC_NAMESPACE_TEMPLATE.format("Dimension"),
             xml_elem=layer)
         for dim in dims:
             ext = xml_helper.try_get_single_element_from_xml(
                 elem="./" + GENERIC_NAMESPACE_TEMPLATE.format("Extent") +
                 '[@name="' + dim.get('name') + '"]',
                 xml_elem=layer)
             dim_dict = {
                 "type": dim.get("name"),
                 "units": dim.get("units"),
                 "extent": ext.text,
             }
             dim_list.append(dim_dict)
     except (IndexError, AttributeError) as error:
         pass
     layer_obj.dimension_list = dim_list
Пример #17
0
    def test_new_service_check_reference_systems(self):
        return
        """ Tests whether the layers have all their reference systems, which are provided by the capabilities document.

        Checks for each layer.

        Returns:

        """
        layers = self.service_wms.get_subelements().select_related(
            'metadata').prefetch_related('metadata__reference_system')
        cap_xml = self.cap_doc_wms.content

        for layer in layers:
            xml_layer_obj = xml_helper.try_get_single_element_from_xml(
                "//Name[text()='{}']/parent::Layer".format(layer.identifier),
                cap_xml)
            if xml_layer_obj is None:
                # it is possible, that there are layers without a real identifier -> this is generally bad.
                # we have to ignore these and concentrate on those, which are identifiable
                continue
            xml_ref_systems = xml_helper.try_get_element_from_xml(
                "./" + GENERIC_NAMESPACE_TEMPLATE.format("SRS"), xml_layer_obj)
            xml_ref_systems_strings = []
            for xml_ref_system in xml_ref_systems:
                xml_ref_systems_strings.append(
                    xml_helper.try_get_text_from_xml_element(xml_ref_system))

            layer_ref_systems = layer.metadata.reference_system.all()
            for ref_system in layer_ref_systems:
                self.assertTrue(
                    ref_system.code in ALLOWED_SRS,
                    msg="Unallowed reference system registered: {}".format(
                        ref_system.code))
                self.assertTrue(
                    ref_system.code in xml_ref_systems_strings,
                    msg=
                    "Reference system registered, which was not in the service: {}"
                    .format(ref_system.code))
Пример #18
0
    def _parse_xml_polygons(self, xml_obj: _Element, xpath_type: str):
        """ Parse the polygon information from the xml document

        Args:
            xml_obj (_Element): The xml element
            xpath_type (str): The element identificator which is determined by SV_ServiceIdentification or MD_DataIdentification
        Returns:
             nothing
        """
        polygons = xml_helper.try_get_element_from_xml(
            xml_elem=xml_obj,
            elem=
            '//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_BoundingPolygon/gmd:polygon/gml:MultiSurface'
            .format(xpath_type))
        if len(polygons) > 0:
            surface_elements = xml_helper.try_get_element_from_xml(
                xml_elem=xml_obj,
                elem=
                "//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_BoundingPolygon/gmd:polygon/gml:MultiSurface/gml:surfaceMember"
                .format(xpath_type))
            for element in surface_elements:
                self.polygonal_extent_exterior.append(
                    self.parse_polygon(element))
        else:
            polygons = xml_helper.try_get_text_from_xml_element(
                xml_obj,
                '//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_BoundingPolygon/gmd:polygon/gml:Polygon'
                .format(xpath_type))
            if polygons is not None:
                polygon = xml_helper.try_get_single_element_from_xml(
                    xml_elem=xml_obj,
                    elem=
                    "//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_BoundingPolygon/gmd:polygon"
                    .format(xpath_type))
                self.polygonal_extent_exterior.append(
                    self.parse_polygon(polygon))
            else:
                self.polygonal_extent_exterior.append(
                    self.parse_bbox(self.bounding_box))
Пример #19
0
    def parse_xml(self):
        """ Reads the needed data from the xml and writes to an ISOMetadata instance (self)

        Returns:
             nothing
        """
        xml = self.raw_metadata
        xml_obj = xml_helper.parse_xml(xml)
        self.file_identifier = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            "//gmd:MD_Metadata/gmd:fileIdentifier/gco:CharacterString")
        self.character_set_code = xml_helper.try_get_attribute_from_xml_element(
            xml_elem=xml_obj,
            attribute="codeListValue",
            elem="//gmd:MD_Metadata/gmd:characterSet/gmd:MD_CharacterSetCode")
        if self.file_identifier is None:
            self.file_identifier = uuid.uuid4()
        self.date_stamp = xml_helper.try_get_text_from_xml_element(
            xml_obj, "//gmd:MD_Metadata/gmd:dateStamp/gco:Date")
        self.last_change_date = xml_helper.try_get_text_from_xml_element(
            xml_obj, "//gmd:MD_Metadata/gmd:dateStamp/gco:Date")

        self.md_standard_name = xml_helper.try_get_text_from_xml_element(
            xml_obj, "//gmd:metadataStandardName/gco:CharacterString")
        self.md_standard_version = xml_helper.try_get_text_from_xml_element(
            xml_obj, "//gmd:metadataStandardVersion/gco:CharacterString")

        self._parse_xml_legal_dates(xml_obj)
        self._parse_xml_legal_reports(xml_obj)

        # try to transform the last_change_date into a datetime object
        try:
            self.last_change_date = parse(self.last_change_date,
                                          tzinfo=timezone.utc)
        except (ValueError, OverflowError, TypeError):
            # if this is not possible due to wrong input, just use the current time...
            self.last_change_date = timezone.now()

        self.hierarchy_level = xml_helper.try_get_attribute_from_xml_element(
            xml_obj, "codeListValue",
            "//gmd:MD_Metadata/gmd:hierarchyLevel/gmd:MD_ScopeCode")
        if self.hierarchy_level == "service":
            xpath_type = "srv:SV_ServiceIdentification"
        else:
            xpath_type = "gmd:MD_DataIdentification"
        self.title = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            "//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:citation/gmd:CI_Citation/gmd:title/gco:CharacterString"
            .format(xpath_type))
        self._parse_xml_dataset_id(xml_obj, xpath_type)
        self.abstract = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            "//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:abstract/gco:CharacterString"
            .format(xpath_type))
        keywords = xml_helper.try_get_element_from_xml(
            xml_elem=xml_obj,
            elem=
            "//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:descriptiveKeywords/gmd:MD_Keywords/gmd:keyword/gco:CharacterString"
            .format(xpath_type))
        for keyword in keywords:
            if keyword.text is not None and keyword not in self.keywords:
                self.keywords.append(
                    xml_helper.try_get_text_from_xml_element(keyword))

        language = xml_helper.try_get_single_element_from_xml(
            xml_elem=xml_obj,
            elem=
            "//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:language/gmd:LanguageCode"
            .format(xpath_type))
        if language and language.text is not None:
            self.language = xml_helper.try_get_text_from_xml_element(language)

        iso_categories = xml_helper.try_get_element_from_xml(
            xml_elem=xml_obj,
            elem=
            "//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:topicCategory/gmd:MD_TopicCategoryCode"
            .format(xpath_type))
        if iso_categories:
            for iso_category in iso_categories:
                self.iso_categories.append(
                    xml_helper.try_get_text_from_xml_element(iso_category))

        # Get all values from <gmd:distributionInfo> which declares the distributionFormat
        formats = xml_helper.try_get_element_from_xml(
            xml_elem=xml_obj,
            elem="//" +
            GENERIC_NAMESPACE_TEMPLATE.format("distributionFormat"))
        if formats:
            for format_elem in formats:
                # get the character value per format
                name_elem = xml_helper.try_get_single_element_from_xml(
                    xml_elem=format_elem,
                    elem=".//" + GENERIC_NAMESPACE_TEMPLATE.format("name"))
                if name_elem is None:
                    continue
                val = xml_helper.try_get_text_from_xml_element(
                    xml_elem=name_elem,
                    elem=".//" +
                    GENERIC_NAMESPACE_TEMPLATE.format("CharacterString"))
                self.formats.append(val)

        self.download_link = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            '//gmd:MD_Metadata/gmd:distributionInfo/gmd:MD_Distribution/gmd:transferOptions/gmd:MD_DigitalTransferOptions/gmd:onLine/gmd:CI_OnlineResource[gmd:function/gmd:CI_OnLineFunctionCode/@codeListValue="download"]/gmd:linkage/gmd:URL'
        )
        self.transfer_size = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            '//gmd:MD_Metadata/gmd:distributionInfo/gmd:MD_Distribution/gmd:transferOptions/gmd:MD_DigitalTransferOptions/gmd:transferSize/gco:Real'
        )
        self.preview_image = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            "//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:graphicOverview/gmd:MD_BrowseGraphic/gmd:fileName/gco:CharacterString"
            .format(xpath_type))
        try:
            self.bounding_box["min_x"] = float(
                xml_helper.try_get_text_from_xml_element(
                    xml_obj,
                    "//gmd:westBoundLongitude/gco:Decimal".format(xpath_type)))
            self.bounding_box["min_y"] = float(
                xml_helper.try_get_text_from_xml_element(
                    xml_obj,
                    "//gmd:southBoundLatitude/gco:Decimal".format(xpath_type)))
            self.bounding_box["max_x"] = float(
                xml_helper.try_get_text_from_xml_element(
                    xml_obj,
                    "//gmd:eastBoundLongitude/gco:Decimal".format(xpath_type)))
            self.bounding_box["max_y"] = float(
                xml_helper.try_get_text_from_xml_element(
                    xml_obj,
                    "//gmd:northBoundLatitude/gco:Decimal".format(xpath_type)))
        except TypeError:
            self.bounding_box = None

        self._parse_xml_polygons(xml_obj, xpath_type)

        self.tmp_extent_begin = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            "//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:extent/gmd:EX_Extent/gmd:temporalElement/gmd:EX_TemporalExtent/gmd:extent/gml:TimePeriod/gml:beginPosition"
            .format(xpath_type))
        if self.tmp_extent_begin is None:
            self.tmp_extent_begin = "1900-01-01"

        self.tmp_extent_end = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            "//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:extent/gmd:EX_Extent/gmd:temporalElement/gmd:EX_TemporalExtent/gmd:extent/gml:TimePeriod/gml:endPosition"
            .format(xpath_type))
        if self.tmp_extent_end is None:
            self.tmp_extent_end = "1900-01-01"

        equivalent_scale = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            "//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:spatialResolution/gmd:MD_Resolution/gmd:equivalentScale/gmd:MD_RepresentativeFraction/gmd:denominator/gco:Integer"
            .format(xpath_type))
        ground_res = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            "//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:spatialResolution/gmd:MD_Resolution/gmd:distance/gco:Distance"
            .format(xpath_type))
        if equivalent_scale is not None and int(equivalent_scale) > 0:
            self.spatial_res_val = equivalent_scale
            self.spatial_res_type = "scaleDenominator"
        elif ground_res is not None and len(ground_res) > 0:
            self.spatial_res_val = ground_res
            self.spatial_res_type = "groundDistance"

        self.ref_system = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            "//gmd:MD_Metadata/gmd:referenceSystemInfo/gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:code/gco:CharacterString"
        )
        self.ref_system_version = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            "//gmd:MD_Metadata/gmd:referenceSystemInfo/gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:version/gco:CharacterString"
        )
        self.ref_system_authority = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            "//gmd:MD_Metadata/gmd:referenceSystemInfo/gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:authority/gmd:CI_Citation/gmd:title/gco:CharacterString"
        )
        epsg_api = EpsgApi()
        if self.ref_system is not None:
            self.ref_system = "EPSG:{}".format(
                epsg_api.get_subelements(self.ref_system).get("code"))

        # gmd:CI_OnLineFunctionCode
        dist_func_elem = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("CI_OnLineFunctionCode"),
            xml_obj)
        self.distribution_function = xml_helper.try_get_attribute_from_xml_element(
            dist_func_elem,
            "codeListValue",
        )
        del dist_func_elem

        # gmd:MD_RepresentativeFraction
        fraction_elem = xml_helper.try_get_single_element_from_xml(
            "//" +
            GENERIC_NAMESPACE_TEMPLATE.format("MD_RepresentativeFraction"),
            xml_obj)
        self.fraction_denominator = xml_helper.try_get_text_from_xml_element(
            fraction_elem,
            ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Integer"))
        del fraction_elem

        # gmd:useLimitation
        limit_elem = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("useLimitation"), xml_obj)
        self.use_limitation = xml_helper.try_get_text_from_xml_element(
            limit_elem,
            ".//" + GENERIC_NAMESPACE_TEMPLATE.format("CharacterString"))
        del limit_elem

        self.lineage = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            "//gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality/gmd:lineage/gmd:LI_Lineage/gmd:statement/gco:CharacterString"
        )

        restriction_code_attr_val = xml_helper.try_get_element_from_xml(
            xml_elem=xml_obj,
            elem=
            '//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:resourceConstraints/gmd:MD_LegalConstraints/gmd:useConstraints/gmd:MD_RestrictionCode/@codeListValue'
            .format(xpath_type))
        if len(restriction_code_attr_val) >= 2:
            legal_constraints = ""
            if restriction_code_attr_val[
                    0] == 'license' and restriction_code_attr_val[
                        1] == 'otherRestrictions':
                other_constraints = xml_helper.try_get_element_from_xml(
                    xml_elem=xml_obj,
                    elem=
                    '//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:useConstraints/gmd:MD_RestrictionCode/@codeListValue="otherRestrictions"]/gmd:otherConstraints/gco:CharacterString'
                    .format(xpath_type))
                for constraint in other_constraints:
                    try:
                        tmp_constraint = xml_helper.try_get_text_from_xml_element(
                            xml_elem=constraint)
                        constraint_json = json.loads(tmp_constraint)
                        self.license_source_note = constraint_json.get(
                            "quelle", None)
                        self.license_json = constraint_json
                    except ValueError:
                        # no, this is not a json!
                        # handle it is a normal text
                        legal_constraints += tmp_constraint + ";"
            self.fees = legal_constraints

        self.access_constraints = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            '//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:accessConstraints/gmd:MD_RestrictionCode/@codeListValue="otherRestrictions"]/gmd:otherConstraints/gco:CharacterString'
            .format(xpath_type))
        self.responsible_party = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            '//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:pointOfContact/gmd:CI_ResponsibleParty/gmd:organisationName/gco:CharacterString'
            .format(xpath_type))
        self.contact_person = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            '//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:pointOfContact/gmd:CI_ResponsibleParty/gmd:individualName/gco:CharacterString'
            .format(xpath_type))
        self.contact_phone = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            '//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:pointOfContact/gmd:CI_ResponsibleParty/gmd:contactInfo/gmd:CI_Contact/gmd:phone/gmd:CI_Telephone/gmd:voice/gco:CharacterString'
            .format(xpath_type))
        self.contact_email = xml_helper.try_get_text_from_xml_element(
            xml_obj,
            '//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:pointOfContact/gmd:CI_ResponsibleParty/gmd:contactInfo/gmd:CI_Contact/gmd:address/gmd:CI_Address/gmd:electronicMailAddress/gco:CharacterString'
            .format(xpath_type))
        update_frequency = xml_helper.try_get_attribute_from_xml_element(
            xml_elem=xml_obj,
            attribute="codeListValue",
            elem=
            '//gmd:MD_Metadata/gmd:identificationInfo/{}/gmd:resourceMaintenance/gmd:MD_MaintenanceInformation/gmd:maintenanceAndUpdateFrequency/gmd:MD_MaintenanceFrequencyCode'
            .format(xpath_type))
        if update_frequency in self.valid_update_frequencies:
            self.update_frequency = update_frequency

        # inspire regulations
        regislations = {"inspire_rules": []}
        with open(INSPIRE_LEGISLATION_FILE, "r", encoding="utf-8") as _file:
            regislations = json.load(_file)
        for regislation in regislations["inspire_rules"]:
            reg = {
                "name": regislation.get("name", None),
                "date": regislation.get("date", "1900-01-01"),
                "pass": None,
            }
            statement = xml_helper.try_get_text_from_xml_element(
                xml_obj,
                '//gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality/gmd:report/gmd:DQ_DomainConsistency/gmd:result/gmd:DQ_ConformanceResult[gmd:specification/gmd:CI_Citation/gmd:title/gco:CharacterString="{}" and gmd:specification/gmd:CI_Citation/gmd:date/gmd:CI_Date/gmd:date/gco:Date="{}"]/gmd:pass/gco:Boolean'
                .format(reg["name"], reg["date"]))
            statement_val = utils.resolve_boolean_attribute_val(statement)
            if statement_val is None:
                reg["pass"] = "******"
                self.inspire_interoperability = False
            else:
                reg["pass"] = statement_val
                # if only one regislation is not fullfilled, we do not have interoperability
                if not statement_val:
                    self.inspire_interoperability = False
            self.interoperability_list.append(reg)
Пример #20
0
    def _parse_operations_metadata(self, upper_elem):
        """ Parses the <Operation> elements inside of <OperationsMetadata>

        Args:
            upper_elem (Element): The upper xml element
        Returns:

        """
        operations_objs = xml_helper.try_get_element_from_xml(
            ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Operation"), upper_elem)

        attribute_map = {
            OGCOperationEnum.GET_CAPABILITIES.value: 'get_capabilities_uri',
            OGCOperationEnum.DESCRIBE_RECORD.value: 'describe_record_uri',
            OGCOperationEnum.GET_RECORDS.value: 'get_records_uri',
            OGCOperationEnum.GET_RECORD_BY_ID.value: 'get_record_by_id_uri',
        }

        for operation in operations_objs:
            operation_name = xml_helper.try_get_attribute_from_xml_element(
                operation,
                "name",
            )
            get_uri = xml_helper.try_get_single_element_from_xml(
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Get"), operation)
            csw_logger.error("Type of returned object of get_uri: {}".format(
                type(get_uri)))

            get_uri = xml_helper.get_href_attribute(
                get_uri) if get_uri is not None else None
            post_uris = xml_helper.try_get_element_from_xml(
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Post"), operation)
            number_of_post_endpoints = post_uris.__len__()
            if (number_of_post_endpoints > 1):
                post_uri = xml_helper.try_get_single_element_from_xml(
                    ".//*[local-name()='Post'][.//ows:Constraint/ows:Value='XML']",
                    operation)
            else:
                post_uri = xml_helper.try_get_single_element_from_xml(
                    ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Post"),
                    operation)
            csw_logger.error(
                "Number of Entries of Post endpoints: {} for operation {}".
                format(number_of_post_endpoints, operation_name))
            csw_logger.error("Type of returned object of post_uri: {}".format(
                type(post_uri)))
            post_uri = xml_helper.get_href_attribute(
                post_uri) if post_uri is not None else None

            if attribute_map.get(operation_name):
                setattr(self,
                        attribute_map.get(operation_name) + '_GET', get_uri)
                setattr(self,
                        attribute_map.get(operation_name) + '_POST', post_uri)
            else:
                # the given operation is not supported for now
                pass

            parameters = self._parse_parameter_metadata(operation)
            output_format = parameters.get("outputFormat", None)
            if output_format is not None:
                self.formats_list.append(
                    MimeType.objects.get_or_create(
                        operation=operation_name,
                        mime_type=output_format,
                    )[0])
Пример #21
0
    def get_service_metadata_from_capabilities(self, xml_obj):
        """ Parse the capability document <Service> metadata into the self object

        Args:
            xml_obj: A minidom object which holds the xml content
        Returns:
             Nothing
        """
        service_xml = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("ServiceIdentification"),
            xml_obj
        )
        self.service_identification_title = xml_helper.try_get_text_from_xml_element(
            xml_elem=service_xml,
            elem="./" + GENERIC_NAMESPACE_TEMPLATE.format("Title")
        )
        if current_task:
            current_task.update_state(
                state=states.STARTED,
                meta={'service': self.service_identification_title, 'phase': 'Parsing main capabilities'}
            )

        self.service_identification_abstract = xml_helper.try_get_text_from_xml_element(
            xml_elem=service_xml,
            elem="./" + GENERIC_NAMESPACE_TEMPLATE.format("Abstract")
        )

        self.service_identification_fees = xml_helper.try_get_text_from_xml_element(
            xml_elem=service_xml,
            elem="./" + GENERIC_NAMESPACE_TEMPLATE.format("Fees")
        )

        self.service_identification_accessconstraints = xml_helper.try_get_text_from_xml_element(
            xml_elem=service_xml,
            elem="./" + GENERIC_NAMESPACE_TEMPLATE.format("AccessConstraints")
        )

        keywords = xml_helper.try_get_element_from_xml(
            xml_elem=service_xml,
            elem="./" + GENERIC_NAMESPACE_TEMPLATE.format("Keywords") +
                 "/" + GENERIC_NAMESPACE_TEMPLATE.format("Keyword")
        )
        kw = []
        for keyword in keywords:
            text = keyword.text
            if text is None:
                continue
            try:
                kw.append(text)
            except AttributeError:
                pass
        self.service_identification_keywords = kw

        self.service_provider_providername = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("ProviderName")
        )

        provider_site_elem = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("ProviderSite"),
            xml_obj
        )
        self.service_provider_url = xml_helper.get_href_attribute(xml_elem=provider_site_elem)
        self.service_provider_responsibleparty_individualname = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("IndividualName")
        )
        self.service_provider_responsibleparty_positionname = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("PositionName")
        )
        self.service_provider_telephone_voice = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("Voice")
        )
        self.service_provider_telephone_facsimile = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("Facsimile")
        )
        self.service_provider_address = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("DeliveryPoint")
        )
        self.service_provider_address_city = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("City")
        )
        self.service_provider_address_state_or_province = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("AdministrativeArea")
        )
        self.service_provider_address_postalcode = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("PostalCode")
        )
        self.service_provider_address_country = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("Country")
        )
        self.service_provider_address_electronicmailaddress = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("ElectronicMailAddress")
        )
        online_resource_elem = xml_helper.try_get_single_element_from_xml(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("OnlineResource")
        )
        self.service_provider_onlineresource_linkage = xml_helper.get_href_attribute(online_resource_elem)
        if self.service_provider_onlineresource_linkage is None or self.service_provider_onlineresource_linkage == "":
            # There are metadatas where no online resource link is given. We need to generate it manually therefore...
            self.service_provider_onlineresource_linkage = service_helper.split_service_uri(self.service_connect_url).get("base_uri")
            self.service_provider_onlineresource_linkage = service_helper.prepare_original_uri_stump(self.service_provider_onlineresource_linkage)

        self.service_provider_contact_hoursofservice = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("HoursOfService")
        )
        self.service_provider_contact_contactinstructions = xml_helper.try_get_text_from_xml_element(
            xml_elem=xml_obj,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("ContactInstructions")
        )
Пример #22
0
    def test_proxy_setting(self):
        return
        """ Tests whether the proxy can be set properly.

        Returns:
        """
        metadata = self.service_wms.metadata

        # To avoid running celery in a separate test instance, we do not call the route. Instead we call the logic, which
        # is used to process access settings directly.
        async_process_securing_access(
            metadata.id,
            use_proxy=True,
            log_proxy=True,
            restrict_access=False,
        )

        self.cap_doc_wms.refresh_from_db()
        doc_unsecured = self.cap_doc_wms.content
        doc_secured = Document.objects.get(
            metadata=metadata,
            document_type=DocumentEnum.CAPABILITY.value,
            is_original=False,
        ).content

        # Check for all operations if the uris has been changed!
        # Do not check for GetCapabilities, since we always change this uri during registration!
        # Make sure all versions can be matched by the code - the xml structure differs a lot from version to version
        service_version = metadata.get_service_version()

        if metadata.is_service_type(OGCServiceEnum.WMS):
            operations = [
                OGCOperationEnum.GET_MAP.value,
                OGCOperationEnum.GET_FEATURE_INFO.value,
                OGCOperationEnum.DESCRIBE_LAYER.value,
                OGCOperationEnum.GET_LEGEND_GRAPHIC.value,
                OGCOperationEnum.GET_STYLES.value,
                OGCOperationEnum.PUT_STYLES.value,
            ]
        elif metadata.is_service_type(OGCServiceEnum.WFS):
            operations = [
                OGCOperationEnum.GET_FEATURE.value,
                OGCOperationEnum.TRANSACTION.value,
                OGCOperationEnum.LOCK_FEATURE.value,
                OGCOperationEnum.DESCRIBE_FEATURE_TYPE.value,
            ]
        else:
            operations = []

        # create xml documents from string documents and fetch only the relevant <Request> element for each
        xml_unsecured = xml_helper.parse_xml(doc_unsecured)
        request_unsecured = xml_helper.try_get_single_element_from_xml(elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("Request"), xml_elem=xml_unsecured)
        xml_secured = xml_helper.parse_xml(doc_secured)
        request_secured = xml_helper.try_get_single_element_from_xml(elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("Request"), xml_elem=xml_secured)

        for operation in operations:
            # Get <OPERATION> element
            operation_unsecured = xml_helper.try_get_single_element_from_xml(".//" + GENERIC_NAMESPACE_TEMPLATE.format(operation), request_unsecured)
            operation_secured = xml_helper.try_get_single_element_from_xml(".//" + GENERIC_NAMESPACE_TEMPLATE.format(operation), request_secured)

            if service_version == OGCServiceVersionEnum.V_1_0_0:
                if metadata.is_service_type(OGCServiceEnum.WMS):
                    # The WMS 1.0.0 specification uses <OPERATION> instead of <GetOPERATION> for any operation element.
                    operation = operation.replace("Get", "")

                    # Get <OPERATION> element again
                    operation_unsecured = xml_helper.try_get_single_element_from_xml(".//" + GENERIC_NAMESPACE_TEMPLATE.format(operation), request_unsecured)
                    operation_secured = xml_helper.try_get_single_element_from_xml(".//" + GENERIC_NAMESPACE_TEMPLATE.format(operation), request_secured)

                # Version 1.0.0 holds the uris in the "onlineResource" attribute of <Get> and <Post>
                get_unsecured = xml_helper.try_get_single_element_from_xml(".//" + GENERIC_NAMESPACE_TEMPLATE.format("Get"), operation_unsecured)
                get_secured = xml_helper.try_get_single_element_from_xml(".//" + GENERIC_NAMESPACE_TEMPLATE.format("Get"), operation_secured)
                post_unsecured = xml_helper.try_get_single_element_from_xml(".//" + GENERIC_NAMESPACE_TEMPLATE.format("Post"), operation_unsecured)
                post_secured = xml_helper.try_get_single_element_from_xml(".//" + GENERIC_NAMESPACE_TEMPLATE.format("Post"), operation_secured)

                online_res = "onlineResource"
                get_unsecured = xml_helper.try_get_attribute_from_xml_element(get_unsecured, online_res)
                get_secured = xml_helper.try_get_attribute_from_xml_element(get_secured, online_res)
                post_unsecured = xml_helper.try_get_attribute_from_xml_element(post_unsecured, online_res)
                post_secured = xml_helper.try_get_attribute_from_xml_element(post_secured, online_res)

                # Assert that all get/post elements are not None
                self.assertIsNotNone(get_secured, msg="The secured uri of '{}' is None!".format(operation))
                self.assertIsNotNone(post_secured, msg="The secured uri of '{}' is None!".format(operation))

                # Assert that the secured version is different from the unsecured one
                self.assertNotEqual(get_unsecured, get_secured, msg="The uri of '{}' has not been secured!".format(operation))
                self.assertNotEqual(post_unsecured, post_secured, msg="The uri of '{}' has not been secured!".format(operation))

                # Assert that the HOST_NAME constant appears in the secured uri
                self.assertContains(get_secured, HOST_NAME)
                self.assertContains(post_secured, HOST_NAME)

            elif service_version == OGCServiceVersionEnum.V_1_1_0 \
                    or service_version == OGCServiceVersionEnum.V_2_0_0 \
                    or service_version == OGCServiceVersionEnum.V_2_0_2:
                # Only WFS
                # Get <OPERATION> element again, since the operation is now identified using an attribute, not an element tag
                operation_unsecured = xml_helper.try_get_single_element_from_xml(
                    ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Operation") + "[@name='" + operation + "']",
                    request_unsecured
                )
                operation_secured = xml_helper.try_get_single_element_from_xml(
                    ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Operation") + "[@name='" + operation + "']",
                    request_secured
                )

                # Version 1.1.0 holds the uris in the href attribute of <Get> and <Post>
                get_unsecured = xml_helper.try_get_single_element_from_xml(".//" + GENERIC_NAMESPACE_TEMPLATE.format("Get"), operation_unsecured)
                get_secured = xml_helper.try_get_single_element_from_xml(".//" + GENERIC_NAMESPACE_TEMPLATE.format("Get"), operation_secured)
                post_unsecured = xml_helper.try_get_single_element_from_xml(".//" + GENERIC_NAMESPACE_TEMPLATE.format("Post"), operation_unsecured)
                post_secured = xml_helper.try_get_single_element_from_xml(".//" + GENERIC_NAMESPACE_TEMPLATE.format("Post"), operation_secured)

                get_unsecured = xml_helper.get_href_attribute(get_unsecured)
                get_secured = xml_helper.get_href_attribute(get_secured)
                post_unsecured = xml_helper.get_href_attribute(post_unsecured)
                post_secured = xml_helper.get_href_attribute(post_secured)

                # Assert that all get/post elements are not None
                self.assertIsNotNone(get_secured, msg="The secured uri of '{}' is None!".format(operation))
                self.assertIsNotNone(post_secured, msg="The secured uri of '{}' is None!".format(operation))

                # Assert that the secured version is different from the unsecured one
                self.assertNotEqual(get_unsecured, get_secured, msg="The uri of '{}' has not been secured!".format(operation))
                self.assertNotEqual(post_unsecured, post_secured, msg="The uri of '{}' has not been secured!".format(operation))

                # Assert that the HOST_NAME constant appears in the secured uri
                self.assertContains(get_secured, HOST_NAME)
                self.assertContains(post_secured, HOST_NAME)

            elif service_version == OGCServiceVersionEnum.V_1_1_1 or service_version == OGCServiceVersionEnum.V_1_3_0:
                # Version 1.1.1 holds the uris in the <OnlineResource> element inside <Get> and <Post>
                get_unsecured = xml_helper.try_get_single_element_from_xml(
                    ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Get")
                    + "/" + GENERIC_NAMESPACE_TEMPLATE.format("OnlineResource"),
                    operation_unsecured
                )
                get_secured = xml_helper.try_get_single_element_from_xml(
                    ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Get")
                    + "/" + GENERIC_NAMESPACE_TEMPLATE.format("OnlineResource"),
                    operation_secured
                )
                post_unsecured = xml_helper.try_get_single_element_from_xml(
                    ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Post")
                    + "/" + GENERIC_NAMESPACE_TEMPLATE.format("OnlineResource"),
                    operation_unsecured
                )
                post_secured = xml_helper.try_get_single_element_from_xml(
                    ".//" + GENERIC_NAMESPACE_TEMPLATE.format("Post")
                    + "/" + GENERIC_NAMESPACE_TEMPLATE.format("OnlineResource"),
                    operation_secured
                )

                get_unsecured = xml_helper.get_href_attribute(get_unsecured)
                get_secured = xml_helper.get_href_attribute(get_secured)
                post_unsecured = xml_helper.get_href_attribute(post_unsecured)
                post_secured = xml_helper.get_href_attribute(post_secured)

                # Assert that both (secure/unsecure) uris are None or none of them
                # This is possible for operations that are not supported by the service
                if get_secured is not None and get_unsecured is not None:
                    self.assertIsNotNone(get_secured, msg="The secured uri of '{}' is None!".format(operation))

                    # Assert that the secured version is different from the unsecured one
                    self.assertNotEqual(get_unsecured, get_secured, msg="The uri of '{}' has not been secured!".format(operation))

                    # Assert that the HOST_NAME constant appears in the secured uri
                    self.assertTrue(HOST_NAME in get_secured)

                if post_secured is not None and post_unsecured is not None:
                    self.assertIsNotNone(post_secured, msg="The secured uri of '{}' is None!".format(operation))
                    self.assertNotEqual(post_unsecured, post_secured, msg="The uri of '{}' has not been secured!".format(operation))
                    self.assertTrue(HOST_NAME in post_secured)
            else:
                pass
Пример #23
0
    def get_service_metadata_from_capabilities(self, xml_obj):
        """ Parses all <Service> element information which can be found in every wms specification since 1.0.0

        Args:
            xml_obj: The iterable xml object tree
        Returns:
            Nothing
        """
        service_xml = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("Service"), xml_obj)

        self.service_file_identifier = xml_helper.try_get_text_from_xml_element(
            service_xml, "./" + GENERIC_NAMESPACE_TEMPLATE.format("Name"))
        self.service_identification_abstract = xml_helper.try_get_text_from_xml_element(
            service_xml, "./" + GENERIC_NAMESPACE_TEMPLATE.format("Abstract"))
        self.service_identification_title = xml_helper.try_get_text_from_xml_element(
            service_xml, "./" + GENERIC_NAMESPACE_TEMPLATE.format("Title"))
        if current_task:
            current_task.update_state(state=states.STARTED,
                                      meta={
                                          'service':
                                          self.service_identification_title,
                                          'phase': "Parsing main capabilities",
                                      })

        self.service_identification_fees = xml_helper.try_get_text_from_xml_element(
            service_xml, "./" + GENERIC_NAMESPACE_TEMPLATE.format("Fees"))
        self.service_identification_accessconstraints = xml_helper.try_get_text_from_xml_element(
            service_xml,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("AccessConstraints"))
        self.service_provider_providername = xml_helper.try_get_text_from_xml_element(
            service_xml,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("ContactInformation") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("ContactPersonPrimary") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("ContactOrganization"))
        authority_elem = xml_helper.try_get_single_element_from_xml(
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("AuthorityURL"),
            xml_elem=xml_obj)
        self.service_provider_url = xml_helper.get_href_attribute(
            authority_elem)
        self.service_provider_contact_contactinstructions = xml_helper.try_get_text_from_xml_element(
            xml_elem=service_xml,
            elem="./" +
            GENERIC_NAMESPACE_TEMPLATE.format("ContactInformation"))
        self.service_provider_responsibleparty_individualname = xml_helper.try_get_text_from_xml_element(
            service_xml,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("ContactInformation") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("ContactPersonPrimary") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("ContactPerson"))
        self.service_provider_responsibleparty_positionname = xml_helper.try_get_text_from_xml_element(
            service_xml,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("ContactInformation") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("ContactPersonPrimary") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("ContactPosition"))
        self.service_provider_telephone_voice = xml_helper.try_get_text_from_xml_element(
            service_xml,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("ContactInformation") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("ContactVoiceTelephone"))
        self.service_provider_telephone_facsimile = xml_helper.try_get_text_from_xml_element(
            service_xml, "./" +
            GENERIC_NAMESPACE_TEMPLATE.format("ContactInformation") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("ContactFacsimileTelephone"))
        self.service_provider_address_electronicmailaddress = xml_helper.try_get_text_from_xml_element(
            service_xml, "./" +
            GENERIC_NAMESPACE_TEMPLATE.format("ContactInformation") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("ContactElectronicMailAddress"))

        keywords = xml_helper.try_get_element_from_xml(
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("KeywordList") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("Keyword"), service_xml)

        kw = []
        for keyword in keywords:
            if keyword is None:
                continue
            kw.append(keyword.text)
        self.service_identification_keywords = kw

        online_res_elem = xml_helper.try_get_single_element_from_xml(
            "//" + GENERIC_NAMESPACE_TEMPLATE.format("Service") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("OnlineResource"), xml_obj)
        link = xml_helper.get_href_attribute(online_res_elem)
        self.service_provider_onlineresource_linkage = link

        self.service_provider_address_country = xml_helper.try_get_text_from_xml_element(
            service_xml,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("ContactInformation") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("ContactAddress") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("Country"))
        self.service_provider_address_postalcode = xml_helper.try_get_text_from_xml_element(
            service_xml,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("ContactInformation") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("ContactAddress") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("PostCode"))
        self.service_provider_address_city = xml_helper.try_get_text_from_xml_element(
            service_xml,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("ContactInformation") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("ContactAddress") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("City"))
        self.service_provider_address_state_or_province = xml_helper.try_get_text_from_xml_element(
            service_xml,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("ContactInformation") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("ContactAddress") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("StateOrProvince"))
        self.service_provider_address = xml_helper.try_get_text_from_xml_element(
            service_xml,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("ContactInformation") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("ContactAddress") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("Address"))

        # parse request uris from capabilities document
        self.parse_request_uris(xml_obj, self)
Пример #24
0
    def _md_metadata_parse_to_dict(self, md_metadata_entries: list) -> list:
        """ Read most important data from MD_Metadata xml element

        Args:
            md_metadata_entries (list): The xml MD_Metadata elements
        Returns:
             ret_list (list): The list containing dicts
        """
        ret_list = []
        for md_metadata in md_metadata_entries:
            md_data_entry = {}

            # Check before anything else, whether this metadata type can be skipped!
            hierarchy_level = xml_helper.try_get_attribute_from_xml_element(
                md_metadata, "codeListValue",
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("hierarchyLevel") +
                "/" + GENERIC_NAMESPACE_TEMPLATE.format("MD_ScopeCode"))
            metadata_type = hierarchy_level
            md_data_entry["metadata_type"] = metadata_type
            if not HARVEST_METADATA_TYPES.get(metadata_type, False):
                continue

            _id = xml_helper.try_get_text_from_xml_element(
                md_metadata,
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("fileIdentifier") +
                "/" + GENERIC_NAMESPACE_TEMPLATE.format("CharacterString"))
            md_data_entry["id"] = _id

            parent_id = xml_helper.try_get_text_from_xml_element(
                md_metadata,
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("parentIdentifier") +
                "/" + GENERIC_NAMESPACE_TEMPLATE.format("CharacterString"))
            md_data_entry["parent_id"] = parent_id

            # A workaround, so we do not need to check whether SV_ServiceIdentification or MD_DataIdentification is present
            # in this metadata: Simply take the direct parent and perform a deeper nested search on the inside of this element.
            # Yes, we could simply decide based on the hierarchyLevel attribute whether to search for SV_xxx or MD_yyy.
            # No, there are metadata entries which do not follow these guidelines and have "service" with MD_yyy
            # Yes, they are important since they can be found in the INSPIRE catalogue (07/2020)
            identification_elem = xml_helper.try_get_single_element_from_xml(
                xml_elem=md_metadata,
                elem=".//" +
                GENERIC_NAMESPACE_TEMPLATE.format("identificationInfo"))
            title = xml_helper.try_get_text_from_xml_element(
                identification_elem,
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("citation") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("CI_Citation") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("title") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("CharacterString"))
            md_data_entry["title"] = title

            language_code = xml_helper.try_get_attribute_from_xml_element(
                md_metadata, "codeListValue",
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("language") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("LanguageCode"))
            md_data_entry["language_code"] = language_code

            date_stamp = xml_helper.try_get_text_from_xml_element(
                md_metadata,
                "./" + GENERIC_NAMESPACE_TEMPLATE.format("dateStamp") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("Date")
            ) or xml_helper.try_get_text_from_xml_element(
                md_metadata,
                "./" + GENERIC_NAMESPACE_TEMPLATE.format("dateStamp") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("DateTime"))
            try:
                md_data_entry["date_stamp"] = parse(date_stamp).replace(
                    tzinfo=utc)
            except TypeError:
                md_data_entry["date_stamp"] = None

            abstract = xml_helper.try_get_text_from_xml_element(
                md_metadata,
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("abstract") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("CharacterString"))
            md_data_entry["abstract"] = abstract

            digital_transfer_elements = xml_helper.try_get_element_from_xml(
                xml_elem=md_metadata,
                elem=".//" +
                GENERIC_NAMESPACE_TEMPLATE.format("MD_DigitalTransferOptions"))
            links = []
            for elem in digital_transfer_elements:
                links_entry = {}
                resource_link = xml_helper.try_get_text_from_xml_element(
                    elem,
                    ".//" + GENERIC_NAMESPACE_TEMPLATE.format("onLine") + "/" +
                    GENERIC_NAMESPACE_TEMPLATE.format("CI_OnlineResource") +
                    "/" + GENERIC_NAMESPACE_TEMPLATE.format("linkage") + "/" +
                    GENERIC_NAMESPACE_TEMPLATE.format("URL"),
                )
                descr = xml_helper.try_get_text_from_xml_element(
                    elem,
                    ".//" + GENERIC_NAMESPACE_TEMPLATE.format("onLine") + "/" +
                    GENERIC_NAMESPACE_TEMPLATE.format("CI_OnlineResource") +
                    "/" + GENERIC_NAMESPACE_TEMPLATE.format("description") +
                    "/" + GENERIC_NAMESPACE_TEMPLATE.format("CharacterString"))
                links_entry["link"] = resource_link
                links_entry["description"] = descr

                if resource_link is not None:
                    # Check on the type of online_resource we found -> could be GetCapabilities
                    query_params = parse_qs(
                        urlparse(resource_link.lower()).query)
                    if OGCOperationEnum.GET_CAPABILITIES.value.lower(
                    ) in query_params.get("request", []):
                        # Parse all possibly relevant data from the dict
                        version = query_params.get("version", [None])
                        service_type = query_params.get("service", [None])
                        md_data_entry[
                            "capabilities_original_url"] = resource_link
                        md_data_entry["service_type"] = service_type[0]
                        md_data_entry["version"] = version[0]
                links.append(links_entry)

            md_data_entry["links"] = links

            keywords = xml_helper.try_get_element_from_xml(
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("keyword") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("CharacterString"),
                md_metadata,
            ) or []
            keywords = [
                xml_helper.try_get_text_from_xml_element(kw) for kw in keywords
            ]
            md_data_entry["keywords"] = keywords

            access_constraints = xml_helper.try_get_text_from_xml_element(
                md_metadata,
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("otherConstraints") +
                "/" + GENERIC_NAMESPACE_TEMPLATE.format("CharacterString"))
            md_data_entry["access_constraints"] = access_constraints

            categories = xml_helper.try_get_element_from_xml(
                ".//" +
                GENERIC_NAMESPACE_TEMPLATE.format("MD_TopicCategoryCode"),
                md_metadata,
            ) or []
            categories = [
                xml_helper.try_get_text_from_xml_element(cat)
                for cat in categories
            ]
            md_data_entry["categories"] = categories

            bbox_elem = xml_helper.try_get_single_element_from_xml(
                ".//" +
                GENERIC_NAMESPACE_TEMPLATE.format("EX_GeographicBoundingBox"),
                md_metadata)
            if bbox_elem is not None:
                extent = [
                    xml_helper.try_get_text_from_xml_element(
                        bbox_elem, ".//" +
                        GENERIC_NAMESPACE_TEMPLATE.format("westBoundLongitude")
                        + "/" + GENERIC_NAMESPACE_TEMPLATE.format("Decimal"))
                    or "0.0",
                    xml_helper.try_get_text_from_xml_element(
                        bbox_elem, ".//" +
                        GENERIC_NAMESPACE_TEMPLATE.format("southBoundLatitude")
                        + "/" + GENERIC_NAMESPACE_TEMPLATE.format("Decimal"))
                    or "0.0",
                    xml_helper.try_get_text_from_xml_element(
                        bbox_elem, ".//" +
                        GENERIC_NAMESPACE_TEMPLATE.format("eastBoundLongitude")
                        + "/" + GENERIC_NAMESPACE_TEMPLATE.format("Decimal"))
                    or "0.0",
                    xml_helper.try_get_text_from_xml_element(
                        bbox_elem, ".//" +
                        GENERIC_NAMESPACE_TEMPLATE.format("northBoundLatitude")
                        + "/" + GENERIC_NAMESPACE_TEMPLATE.format("Decimal"))
                    or "0.0",
                ]
                # There are metadata with wrong vertex notations like 50,3 instead of 50.3
                # We should just drop them, since they are not compatible with the specifications but in here, we make an
                # exception and replace , since it's quite easy
                extent = [vertex.replace(",", ".") for vertex in extent]
                try:
                    bounding_geometry = GEOSGeometry(
                        Polygon.from_bbox(bbox=extent), srid=DEFAULT_SRS)
                except Exception:
                    # Log malicious extent!
                    csw_logger.warning(
                        CSW_EXTENT_WARNING_LOG_TEMPLATE.format(
                            _id, self.metadata.title, extent))
                    bounding_geometry = DEFAULT_SERVICE_BOUNDING_BOX_EMPTY
            else:
                bounding_geometry = DEFAULT_SERVICE_BOUNDING_BOX_EMPTY

            md_data_entry["bounding_geometry"] = bounding_geometry
            md_data_entry["contact"] = self._create_contact_from_md_metadata(
                md_metadata)
            md_data_entry["formats"] = self._create_formats_from_md_metadata(
                md_metadata)

            # Load non-metadata data
            # ToDo: Should harvesting persist non-metadata data?!
            #described_resource = None
            #metadata = None
            #if hierarchy_level == MetadataEnum.DATASET.value:
            #    described_resource = self._create_dataset_from_md_metadata(md_metadata, metadata)
            #    described_resource.metadata = metadata
            #    described_resource.is_active = True
            #    described_resource.save()

            ret_list.append(md_data_entry)
        return ret_list
Пример #25
0
def _overwrite_capabilities_keywords(xml_obj: _Element, metadata: Metadata,
                                     _type: str):
    """ Overwrites existing capabilities keywords with metadata editor input

    Args:
        xml_obj (_Element): The parent xml object which holds the KeywordList element
        metadata (Metadata): The metadata object which holds the edited keyword data
        _type (str): Defines if this is a wms or wfs
    Returns:
         nothing
    """
    ns_prefix = ""
    keyword_container_tag = "KeywordList"
    keyword_prefix = ""
    keyword_ns_map = {}

    if _type == 'wfs':
        ns_keyword_prefix_s = "ows"
        ns_prefix = "wfs:"
        if metadata.is_root():
            # for the <ows:ServiceIdentification> element we need the prefix "ows:"
            ns_prefix = "ows:"
        keyword_container_tag = "Keywords"
        keyword_prefix = "{" + XML_NAMESPACES[ns_keyword_prefix_s] + "}"
        keyword_ns_map[ns_keyword_prefix_s] = XML_NAMESPACES[
            ns_keyword_prefix_s]

    xml_keywords_list_obj = xml_helper.try_get_single_element_from_xml(
        "./" + GENERIC_NAMESPACE_TEMPLATE.format(keyword_container_tag),
        xml_obj)

    if xml_keywords_list_obj is None:
        # there are no keywords in this capabilities for this element yet
        # we need to add an element first!
        try:
            xml_keywords_list_obj = xml_helper.create_subelement(
                xml_obj,
                "{}{}".format(keyword_prefix, keyword_container_tag),
                after="{}Abstract".format(ns_prefix),
                nsmap=keyword_ns_map)
        except (TypeError, ValueError) as e:
            # there seems to be no <Abstract> element. We add simply after <Title> and also create a new Abstract element
            xml_keywords_list_obj = xml_helper.create_subelement(
                xml_obj,
                "{}{}".format(keyword_prefix, keyword_container_tag),
                after="{}Title".format(ns_prefix))
            xml_helper.create_subelement(xml_obj,
                                         "{}".format("Abstract"),
                                         after="{}Title".format(ns_prefix))

    xml_keywords_objs = xml_helper.try_get_element_from_xml(
        "./" + GENERIC_NAMESPACE_TEMPLATE.format("Keyword"),
        xml_keywords_list_obj) or []

    # first remove all persisted keywords
    for kw in xml_keywords_objs:
        xml_keywords_list_obj.remove(kw)

    # then add all edited
    for kw in metadata.keywords.all():
        xml_keyword = xml_helper.create_subelement(
            xml_keywords_list_obj,
            "{}Keyword".format(keyword_prefix),
            nsmap=keyword_ns_map)
        xml_helper.write_text_to_element(xml_keyword, txt=kw.keyword)
Пример #26
0
    def _create_contact_from_md_metadata(self,
                                         md_metadata: Element) -> Organization:
        """ Creates an Organization (Contact) instance from MD_Metadata.

        Holds the basic information

        Args:
            md_metadata (Element): The xml element
        Returns:
             org (Organization): The organization element
        """
        resp_party_elem = xml_helper.try_get_single_element_from_xml(
            ".//" + GENERIC_NAMESPACE_TEMPLATE.format("CI_ResponsibleParty"),
            md_metadata)
        if resp_party_elem is None:
            return None

        organization_name = xml_helper.try_get_text_from_xml_element(
            resp_party_elem,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("organisationName") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("CharacterString")) or ""
        person_name = xml_helper.try_get_text_from_xml_element(
            resp_party_elem,
            "./" + GENERIC_NAMESPACE_TEMPLATE.format("individualName") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("CharacterString")) or ""
        phone = xml_helper.try_get_text_from_xml_element(
            resp_party_elem,
            ".//" + GENERIC_NAMESPACE_TEMPLATE.format("CI_Telephone") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("voice") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("CharacterString")) or ""
        facsimile = xml_helper.try_get_text_from_xml_element(
            resp_party_elem,
            ".//" + GENERIC_NAMESPACE_TEMPLATE.format("CI_Telephone") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("facsimile") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("CharacterString")) or ""

        # Parse address information, create fallback values
        address = ""
        city = ""
        postal_code = ""
        country = ""
        email = ""
        state = ""
        address_elem = xml_helper.try_get_single_element_from_xml(
            ".//" + GENERIC_NAMESPACE_TEMPLATE.format("CI_Address"),
            md_metadata)
        if address_elem is not None:
            address = xml_helper.try_get_text_from_xml_element(
                address_elem, ".//" +
                GENERIC_NAMESPACE_TEMPLATE.format("deliveryPoint") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("CharacterString")) or ""
            city = xml_helper.try_get_text_from_xml_element(
                address_elem,
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("city") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("CharacterString")) or ""
            postal_code = xml_helper.try_get_text_from_xml_element(
                address_elem,
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("postalCode") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("CharacterString")) or ""
            country = xml_helper.try_get_text_from_xml_element(
                address_elem,
                ".//" + GENERIC_NAMESPACE_TEMPLATE.format("country") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("CharacterString")) or ""
            email = xml_helper.try_get_text_from_xml_element(
                address_elem, ".//" +
                GENERIC_NAMESPACE_TEMPLATE.format("electronicMailAddress") +
                "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("CharacterString")) or ""
            state = xml_helper.try_get_text_from_xml_element(
                address_elem, ".//" +
                GENERIC_NAMESPACE_TEMPLATE.format("administrativeArea") + "/" +
                GENERIC_NAMESPACE_TEMPLATE.format("CharacterString")) or ""
        is_auto_generated = True
        description = xml_helper.try_get_text_from_xml_element(
            resp_party_elem,
            ".//" + GENERIC_NAMESPACE_TEMPLATE.format("CI_OnlineResource") +
            "/" + GENERIC_NAMESPACE_TEMPLATE.format("linkage") + "/" +
            GENERIC_NAMESPACE_TEMPLATE.format("URL")) or ""
        try:
            org = Organization.objects.create(
                person_name=person_name,
                organization_name=organization_name,
                phone=phone,
                facsimile=facsimile,
                address=address,
                city=city,
                postal_code=postal_code,
                country=country,
                email=email,
                state_or_province=state,
                is_auto_generated=is_auto_generated,
                description=description,
            )
        except IntegrityError:
            org = Organization.objects.get(
                person_name=person_name,
                organization_name=organization_name,
                phone=phone,
                facsimile=facsimile,
                address=address,
                city=city,
                postal_code=postal_code,
                country=country,
                email=email,
                state_or_province=state,
                is_auto_generated=is_auto_generated,
                description=description,
            )
        return org