Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: build xml elements #720

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

Rossi-Luciano
Copy link
Collaborator

O que esse PR faz?

Este PR introduz três funções que geram estruturas XML usando a biblioteca xml.etree.ElementTree. Ele visa resolver a necessidade de criação dinâmica de elementos XML, tais como <article>, <contrib>, e <journal-meta>, com base em dados de entrada.

Onde a revisão poderia começar?

A revisão pode começar pelos arquivos que contêm as seguintes funções:

  • build_article_node() no arquivo article.py
  • build_contrib_author() no arquivo contrib.py
  • build_journal_meta() no arquivo journal_meta.py

Como este poderia ser testado manualmente?

  1. Crie um script Python para importar as funções dos arquivos relevantes.

  2. Forneça dados de entrada similares aos exemplos abaixo e execute as funções para gerar o XML.

Exemplo de dados para build_article_node:

article_data = {
    "dtd-version": "1.1",
    "specific-use": "research",
    "article-type": "original",
    "xml:lang": "en"
}

Exemplo de dados para build_contrib_author:

data = {
    "contrib_type": "author",
    "contrib_ids": {
        "orcid": "0000-0001-8528-2091",
        "scopus": "24771926600"
    },
    "surname": "Einstein",
    "given_names": "Albert",
    "affiliations": [
        {"rid": "aff1", "text": "1"}
    ]
}

Exemplo de dados para build_journal_meta:

data = {
    "journal_ids": {
        "nlm-ta": "Braz J Med Biol Res",
        "publisher-id": "bjmbr"
    },
    "journal_title": "Brazilian Journal of Medical and Biological Research",
    "abbrev_journal_title": "Braz. J. Med. Biol. Res.",
    "issn": {
        "epub": "1414-431X",
        "ppub": "0100-879X"
    },
    "publisher_name": "Associação Brasileira de Divulgação Científica"
}
  1. Verifique a saída XML gerada pelas funções, certificando-se de que todos os elementos foram corretamente criados e formatados.

Algum cenário de contexto que queira dar?

NA

Screenshots

NA

Quais são tickets relevantes?

NA

Referências

NA

Comment on lines 32 to 43
journal_ids = journal_meta_elem.findall("journal-id")
self.assertEqual(len(journal_ids), 2)
self.assertEqual(journal_ids[0].get("journal-id-type"), "nlm-ta")
self.assertEqual(journal_ids[0].text, "Braz J Med Biol Res")
self.assertEqual(journal_ids[1].get("journal-id-type"), "publisher-id")
self.assertEqual(journal_ids[1].text, "bjmbr")

# Verifica o grupo de títulos <journal-title-group>
journal_title_group = journal_meta_elem.find("journal-title-group")
self.assertIsNotNone(journal_title_group)

# Verifica se <journal-title> foi criado corretamente
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano o ideal é que cada método de teste tenha 1 assert. O motivo disto é que se houver failure, o teste vai parar no primeiro failure.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano adicione casos de usos mais diversos que seriam o que acontece na ausência de alguns valores ou chaves do dicionário, ou o que ocorre se o usuário fornece chaves diferentes das esperadas?

Copy link
Member

@robertatakenaka robertatakenaka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano ficou muito bom. Mas veja as melhorias nos testes, principalmente a questão de tratar a ausência de chaves esperadas e inesperadas no dicionário.

name_elem.append(surname_elem) # Adiciona <surname> ao <name>
if "surname" in data: # Adiciona <surname> somente se estiver presente no dicionário
surname_elem = ET.Element("surname")
surname_elem.text = data.get("surname", "") # Mesmo se for vazio, cria o elemento
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano

surname_elem.text = data.get("surname", "")

Este código não atribui "" para {"surname": None}

In [1]: d = {"a": None}

In [2]: d.get("a", "")

In [3]: print(d.get("a", ""))
None

No lugar disso, use:

surname_elem.text = data["surname"] or ""

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano mas me parece, vendo os testes, que se você colocar apenas surname_elem.text = data["surname"] é o suficiente

Comment on lines 54 to 57
if rid is not None:
xref_elem.set("rid", rid)
if text is not None:
xref_elem.text = text
Copy link
Member

@robertatakenaka robertatakenaka Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano combinamos que se o valor do atributo é None, o atributo aparece com valor de "". Neste trecho você está condicionando a inserção do atributo rid ao valor. Além disso, como rid é obrigarório, use o acesso direto à chave e não .get(key)
Por que não fez:

xref_elem = ET.Element("xref", attrib={"ref-type": "aff", "rid": rid or ""})

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ou melhor ainda:

# rid é obrigatório, a ausência da chave deveria levantar exceção
xref_elem = ET.Element("xref", attrib={"ref-type": "aff", "rid": xref_data["rid"]})

journal_title_elem = ET.Element("journal-title")
journal_title_elem.text = data.get('journal_title', '')
journal_title_group.append(journal_title_elem) # Adiciona <journal-title> ao <journal-title-group>
journal_title_elem.text = data.get('journal_title', '') or ''
Copy link
Member

@robertatakenaka robertatakenaka Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano use: journal_title_elem.text = data.get('journal_title') or ''
Isso resolve tanto a ausência de chave quanto de valor da chave. Faça uma busca por ', '') or '' e corrija

"""Método auxiliar para construção e comparação do XML gerado"""
journal_meta_elem = build_journal_meta(self.empty_data)
generated_xml_str = ET.tostring(journal_meta_elem, encoding="unicode", method="xml")
self.assertEqual(generated_xml_str.strip(), expected_xml_str.strip())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano uma dúvida minha: se der falha, você conseguirá facilmente identificar onde, sendo que este método é chamado em todos os métodos de teste?

# Cria e adiciona o <name> com <surname> e <given-names>
name_elem = ET.Element("name")
# Cria e adiciona o <name> com <surname> e <given-names> somente se existirem no dicionário
if "surname" in data or "given_names" in data:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano adicione prefix e suffix. Consulte a documentação para conferir se já exigência de ordem

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano considerar também o contrib com collab

journal_title_elem = ET.Element("journal-title")
journal_title_elem.text = data.get('journal_title', '') or ''
journal_title_group.append(journal_title_elem)
if 'journal_title' in data:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano aqui vc já testou que a chave existe, então na linha 44, use data['journal_title']


# Cria e adiciona o <name> com <surname> e <given-names> somente se existirem no dicionário
if "surname" in data or "given_names" in data:
if any(key in data for key in ("surname", "given_names", "prefix", "suffix")):
Copy link
Member

@robertatakenaka robertatakenaka Oct 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano
Pode usar o seguinte:

if any(data.get(key) for key in ("surname", "given_names", "prefix", "suffix")):

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants