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

Crossmark #465

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ae138fa
Adiciona 'xml_crossref_crossmark_pipe' com seu teste correspondente
Rossi-Luciano Aug 29, 2023
80c58fc
Modifica a importação de 'crossref'
Rossi-Luciano Aug 29, 2023
0a443b6
Adiciona 'xml_crossref_crossmark_policy_pipe' com seu respectivo teste
Rossi-Luciano Aug 29, 2023
6324e5e
Adiciona 'xml_crossref_crossmark_domains_pipe' e o teste correspondente
Rossi-Luciano Sep 3, 2023
75b8f89
Adiciona 'xml_crossref_crossmark_updates_pipe' e o respectivo teste
Rossi-Luciano Sep 3, 2023
47c57b0
Adiciona 'xml_crossref_crossmark_custom_metadata_pipe' e o respectivo…
Rossi-Luciano Sep 3, 2023
6af2832
Corrige importação
Rossi-Luciano Sep 3, 2023
977442c
Refatora 'xml_crossref_crossmark_pipe'
Rossi-Luciano Sep 6, 2023
3c75217
Refatora 'xml_crossref_crossmark_policy_pipe'
Rossi-Luciano Sep 6, 2023
68b3fe2
Refatora 'xml_crossref_crossmark_domains_pipe'
Rossi-Luciano Sep 6, 2023
6712578
Refatora 'xml_crossref_crossmark_updates_pipe'
Rossi-Luciano Sep 6, 2023
dc4c46e
Refatora 'xml_crossref_crossmark_custom_metadata_pipe'
Rossi-Luciano Sep 6, 2023
baaffd8
Adiciona 'test_xml_crossref_crossmark_updates_correction_pipe'
Rossi-Luciano Sep 6, 2023
bc6036d
Adiciona 'test_xml_crossref_crossmark_updates_correction_exists_updat…
Rossi-Luciano Sep 6, 2023
e990ef5
Refatora 'test_xml_crossref_crossmark_updates_research_article_pipe'
Rossi-Luciano Sep 6, 2023
db301b8
Refatora 'test_xml_crossref_crossmark_custom_metadata_pipe'
Rossi-Luciano Sep 6, 2023
0246f96
Adiciona exemplos para o XML Crosref resultante de cada função
Rossi-Luciano Sep 11, 2023
b15e7e7
Adiciona teste para verificar o comportamento quando da ausência de '…
Rossi-Luciano Sep 11, 2023
a7dfaab
Adiciona teste para verificação do comportamento quando o XML é 'rese…
Rossi-Luciano Sep 11, 2023
5b161c9
Adiciona dicionário para correpondência de tipos
Rossi-Luciano Sep 13, 2023
7402902
Melhora apresentação
Rossi-Luciano Sep 13, 2023
628d165
Importa dicionário de tipos
Rossi-Luciano Sep 13, 2023
9a357e2
Adiciona função auxiliar
Rossi-Luciano Sep 13, 2023
f28dfd8
Adiciona dicionário de informações sobre 'update' como parâmetro
Rossi-Luciano Sep 13, 2023
94abd13
Refatora 'xml_crossref_crossmark_updates_pipe'
Rossi-Luciano Sep 13, 2023
3b5fdde
Remove 'label' do teste
Rossi-Luciano Sep 13, 2023
f3e1b8c
Adiciona dicionários como parâmetro nos testes
Rossi-Luciano Sep 13, 2023
cb68638
Refatora 'xml_crossref_crossmark_updates_article_without_related_arti…
Rossi-Luciano Sep 13, 2023
7e2d990
Refatora 'test_xml_crossref_crossmark_updates_correction_exists_updat…
Rossi-Luciano Sep 13, 2023
ea002d3
Adiciona 'test_xml_crossref_crossmark_updates_research_article_withou…
Rossi-Luciano Sep 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 191 additions & 0 deletions packtools/sps/formats/crossref.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
article_titles,
article_doi_with_lang,
article_citations,
related_articles,
)

SUPPLBEG_REGEX = re.compile(r'^0 ')
Expand Down Expand Up @@ -1401,6 +1402,196 @@ def xml_crossref_pid_pipe(xml_crossref, xml_tree):
xml_crossref.find('./body/journal/journal_article').append(publisher_item)


def xml_crossref_crossmark_pipe(xml_crossref):
"""
Adiciona o elemento 'crossmark' ao XML Crossref.

Parameters
----------
xml_crossref : lxml.etree._Element
Elemento XML no padrão CrossRef em construção

Returns
-------
None
"""
crossmark = ET.Element("crossmark")
article_el = xml_crossref.find('./body/journal/journal_article')
article_el.append(crossmark)


def xml_crossref_crossmark_policy_pipe(xml_crossref, 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 perfeito! Eu acredito que sim este dado é externo ao XML SPS, logo deve ser informado via um dicionário.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

"""
Adiciona o elemento 'crossmark_policy' ao XML Crossref.

Parameters
----------
xml_crossref : lxml.etree._Element
Elemento XML no padrão CrossRef em construção

data : dict
Dicionário com dados suplementares para a criação do xml_crossref como, por exemplo:
data = {
"crossmark_policy": "10.5555/crossmark_policy"
}

Returns
-------
None
"""
policy_value = data.get("crossmark_policy")

if policy_value:
crossmark_el = xml_crossref.find('./body/journal/journal_article/crossmark')
policy_el = ET.Element("crossmark_policy")
policy_el.text = policy_value
crossmark_el.append(policy_el)


def xml_crossref_crossmark_domains_pipe(xml_crossref, data):
"""
Adiciona o elemento 'crossmark_domains' ao XML Crossref.

Parameters
----------
xml_crossref : lxml.etree._Element
Elemento XML no padrão CrossRef em construção

data : dict
Dicionário com dados suplementares para a criação do xml_crossref como, por exemplo:
data = {
"crossmark_domains": ["psychoceramics.labs.crossref.org"],
"crossmark_domain_exclusive": "false"
}

Returns
-------
None
"""
crossmark_domains = data.get("crossmark_domains")
crossmark_domain_exclusive = data.get("crossmark_domain_exclusive")

crossmark_el = xml_crossref.find('./body/journal/journal_article/crossmark')

if crossmark_domains:
crossmark_domains_el = ET.Element("crossmark_domains")
for crossmark_domain_value in crossmark_domains:
crossmark_domain_el = ET.Element("crossmark_domain")
domain_el = ET.Element("domain")
domain_el.text = crossmark_domain_value
crossmark_domain_el.append(domain_el)
crossmark_domains_el.append(crossmark_domain_el)
crossmark_el.append(crossmark_domains_el)

if crossmark_domain_exclusive:
crossmark_domain_exclusive_el = ET.Element("crossmark_domain_exclusive")
crossmark_domain_exclusive_el.text = crossmark_domain_exclusive
crossmark_el.append(crossmark_domain_exclusive_el)


def xml_crossref_crossmark_updates_pipe(xml_crossref, xml_tree):
"""
Adiciona o elemento 'update' ao XML Crossref se houver um DOI de atualização.
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 coloca exemplo de como deve ficar o updates

Copy link
Collaborator Author

Choose a reason for hiding this comment

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


Parameters
----------
xml_crossref : lxml.etree._Element
Elemento XML no padrão CrossRef em construção

xml_tree : lxml.etree._Element
Elemento XML no padrão SciELO com os dados sobre atualizações

Returns
-------
None
"""
# Obter informações necessárias do XML SciELO
update_type = article_and_subarticles.ArticleAndSubArticles(xml_tree).main_article_type
update_doi = [item.get('href') for item in related_articles.RelatedItems(xml_tree).related_articles][0]

if update_doi:
update_el = ET.Element("update")
update_el.text = update_doi
update_el.set("type", update_type)
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 suspeito que o update_type é do related-article.

Se o artigo em que estou do XML é um artigo e tem related-article para errata, o update_type é errata e não "artigo". Sim ou não?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Vou compartilhar aqui minhas impressões sobre a lógica do Crossmark...
Um artigo do tipo research-article não terá uma referência a outro que esteja ligado a algum tipo de atualização (pelo menos nas minhas observações).
Quando um artigo deste tipo necessita de alguma atualização, outro documento XML fará referência ao primeiro. Em outras palavras, uma errata é um documento do tipo correction que tem um related-article para o research-article que é o alvo da correção (atualização), não encontrei exemplos que evidenciem o contrário, ou seja, research-article referenciando um correction.
Considerando esse contexto, para documentos que atualizam outros considerei como atributo label o mesmo conteúdo de type como no exemplo a seguir:
<update type="correction" label="Correction">10.1590/1519-6984.263364</update>
Observei esse padrão nos exemplos disponíveis em https://github.com/CrossRef/CrossMark-Examples/tree/master.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Veja alguns exemplo encontrados no link anterior:
<update type="retraction" label="Retraction" date="2009-09-14">10.5555/12345678</update>
<update type="correction" label="Correction" date="2012-02-29">10.5555/12345679</update>
<update type="interesting_update" label="Interesting Update" date="2012-03-15">10.5555/12345680</update>
<update type="correction" label="Correction" date="2012-05-12">10.5555/12345681</update>
<update type="clarification" label="Clarification" date="2012-12-29">10.5555/666655554444</update>
Penso eu que os atributos type nos casos acima se referem ao tipo do documento que atualiza outro.

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 conforme eu havia comentado sobre

não encontrei exemplos que evidenciem o contrário, ou seja, research-article referenciando um correction.

é um "defeito" do XML, pois deveria haver esta indicação que impedirá de gerar corretamente o XML com crossmark.

Então, considere que sim em research-article, quando houver errata, deve haver também o related-article indicando a errata.

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 os valores de type são valores controlados. Verifique se está considerando corretamente: https://data.crossref.org/schemas/common5.3.1.xsd. Busque por <xsd:attribute name="type" use="required" type="cm_update_type">. O atributo label não é obrigatório, por favor, remover.

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 Na função que adiciona o elemento update, considere também que os itens podem vir pelo parâmetro data:

{
"related-articles": [
    {"related-article-type": "", "href": "", "date": ""},
    {"related-article-type": "", "href": "", "date": ""},   
]}

Ou seja, a função deve montar update com os dados do XML e os dados passados por parâmetros

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

update_el.set("label", update_type.capitalize())

# Verificar se já existe um elemento 'updates' no XML Crossref
crossmark_el = xml_crossref.find('./body/journal/journal_article/crossmark')
updates_el = crossmark_el.find('updates')

if updates_el is None:
updates_el = ET.Element("updates")
crossmark_el.append(updates_el)

updates_el.append(update_el)


def xml_crossref_crossmark_custom_metadata_pipe(xml_crossref, xml_tree, data):
"""
Adiciona o elemento 'custom_metadata' ao xml_crossref.

Parameters
----------
xml_crossref : lxml.etree._Element
Elemento XML no padrão CrossRef em construção

xml_tree : lxml.etree._Element
Elemento XML no padrão SciELO com os dados sobre atualizações

data : dict
Dicionário com dados suplementares para a criação do xml_crossref como, por exemplo:
data = {
"assertions": [
{
"name": "remorse",
"label": "Level of Remorse",
"group_name": "publication_notes",
"group_label": "Publication Notes",
"text": "90%"
}
]
}

Returns
-------
None
"""
history = dates.ArticleDates(xml_tree).history_dates_dict

for order, item in enumerate(history):
event = history[item]
data.get("assertions").insert(order,
{
"name": event.get("type"),
"label": event.get("type").capitalize(),
"group_name": "publication_history",
"group_label": "Publication History",
"order": str(order),
"text": '-'.join([event.get("year"), event.get("month"), event.get("day")])
}
)

assertions = data.get("assertions")

if assertions:
crossmark_el = xml_crossref.find('./body/journal/journal_article/crossmark')
custom_metadata_el = ET.Element("custom_metadata")

for assertion in assertions:
text = assertion.get("text")
if text:
assertion_el = ET.Element("assertion")
assertion_el.text = text
attributes = ["name", "label", "group_name", "group_label", "order"]
for attr in attributes:
value = assertion.get(attr)
if value:
assertion_el.set(attr, value)
custom_metadata_el.append(assertion_el)

crossmark_el.append(custom_metadata_el)


def xml_crossref_elocation_pipe(xml_crossref, xml_tree):
"""
Adiciona o elemento 'item_number' ao xml_crossref.
Expand Down
Loading