<commit_before>from lxml import etree

from share.util.graph import MutableGraph
from share.util.names import get_related_agent_name

from share.oaipmh.util import format_datetime, ns, nsmap, SubEl
from share.metadata_formats.base import MetadataFormatter


class OaiDcFormatter(MetadataFormatter):
    """builds an XML fragment in dublin core format, meant to be included within the
    <metadata> element of an OAI-PMH `listRecords` or `showRecord` response

    see https://www.openarchives.org/OAI/openarchivesprotocol.html for more details
    """

    def format(self, normalized_datum):
        mgraph = MutableGraph.from_jsonld(normalized_datum.data)
        central_work = mgraph.get_central_node(guess=True)

        if (
            not central_work
            or central_work.concrete_type != 'abstractcreativework'
            or central_work['is_deleted']
        ):
            return self.format_as_deleted()

        dc_formatted = self.build_dublin_core(central_work)
        return etree.tostring(dc_formatted, encoding='unicode')

    def build_dublin_core(self, work_node):
        dc_element = etree.Element(
            ns('oai_dc', 'dc'),
            attrib={
                ns('xsi', 'schemaLocation'): 'http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd'
            },
            nsmap=nsmap('oai_dc', 'dc', 'xsi'),
        )
        SubEl(dc_element, ns('dc', 'title'), work_node['title'])

        for creator_name in self._get_related_agent_names(work_node, {'creator'}):
            SubEl(dc_element, ns('dc', 'creator'), creator_name)

        subject_names = {
            subject_node['name']
            for subject_node in work_node['subjects']
        }
        for subject_name in sorted(subject_names):<commit_msg>fix: oai_dc formatter breaks on deletions<commit_after>from lxml import etree

from share.util.graph import MutableGraph
from share.util.names import get_related_agent_name

from share.oaipmh.util import format_datetime, ns, nsmap, SubEl
from share.metadata_formats.base import MetadataFormatter


class OaiDcFormatter(MetadataFormatter):
    """builds an XML fragment in dublin core format, meant to be included within the
    <metadata> element of an OAI-PMH `listRecords` or `showRecord` response

    see https://www.openarchives.org/OAI/openarchivesprotocol.html for more details
    """

    def format(self, normalized_datum):
        mgraph = MutableGraph.from_jsonld(normalized_datum.data)
        central_work = mgraph.get_central_node(guess=True)

        if (
            not central_work
            or central_work.concrete_type != 'abstractcreativework'
            or central_work['is_deleted']
        ):
            return self.format_as_deleted(None)

        dc_formatted = self.build_dublin_core(central_work)
        return etree.tostring(dc_formatted, encoding='unicode')

    def build_dublin_core(self, work_node):
        dc_element = etree.Element(
            ns('oai_dc', 'dc'),
            attrib={
                ns('xsi', 'schemaLocation'): 'http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd'
            },
            nsmap=nsmap('oai_dc', 'dc', 'xsi'),
        )
        SubEl(dc_element, ns('dc', 'title'), work_node['title'])

        for creator_name in self._get_related_agent_names(work_node, {'creator'}):
            SubEl(dc_element, ns('dc', 'creator'), creator_name)

        subject_names = {
            subject_node['name']
            for subject_node in work_node['subjects']
        }
        for subject_name in sorted(subject_names):
{'fraction_non_alphanumeric': 0.10513245033112582, 'fraction_numerical': 0.002207505518763797, 'mean_word_length': 2.9574235807860263, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 6, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4916816', 'n_tokens_mistral': 1142, 'n_tokens_neox': 1114, 'n_words': 230}