Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 27 additions & 3 deletions packtools/sps/formats/pubmed.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,12 +401,36 @@ def xml_pubmed_author_list(xml_pubmed, xml_tree):
xml_pubmed.append(author_list_tag)


# Maps SPS `@article-type` to the PubMed closed PublicationType vocabulary
# (https://www.ncbi.nlm.nih.gov/books/NBK3828/). Only pairs with a clear,
# unambiguous equivalence are listed here -- see get_publication_type for
# what happens to the rest.
PUBLICATION_TYPE_MAPPING = {
"research-article": "Journal Article",
"case-report": "Case Reports",
"review-article": "Review",
"letter": "Letter",
"editorial": "Editorial",
"retraction": "Retraction Notice",
"partial-retraction": "Retraction Notice",
"correction": "Published Erratum",
"data-article": "Journal Article",
"expression-of-concern": "Expression of Concern",
}


def get_publication_type(xml_tree):
publication_type = article_and_subarticles.ArticleAndSubArticles(
"""
`PublicationType` is optional in the PubMed DTD (`PublicationType*`), so
an `@article-type` with no safe mapping (e.g. "obituary", "book-review",
"other") is omitted rather than defaulted to "Journal Article" -- forcing
a value into this closed vocabulary would misrepresent the document type
to PubMed's indexing, which is worse than leaving it out. See issue #1240.
"""
article_type = article_and_subarticles.ArticleAndSubArticles(
xml_tree
).main_article_type
if publication_type is not None:
return publication_type.replace("-", " ").title()
return PUBLICATION_TYPE_MAPPING.get(article_type)


def xml_pubmed_publication_type(xml_pubmed, xml_tree):
Expand Down
90 changes: 86 additions & 4 deletions tests/sps/formats/test_pubmed.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,12 +1013,9 @@ def test_xml_pubmed_author_list_without_author(self):
self.assertEqual(obtained, expected)

def test_xml_pubmed_publication_type(self):
# TODO
# Originalmente, espera-se que o valor da tag <PublicationType> seja Journal Article
# Nos arquivos de exemplo há somente a referencia a Research Article, o qual foi utilizado
expected = (
'<Article>'
'<PublicationType>Research Article</PublicationType>'
'<PublicationType>Journal Article</PublicationType>'
'</Article>'
)
xml_pubmed = ET.fromstring(
Expand All @@ -1037,6 +1034,91 @@ def test_xml_pubmed_publication_type(self):

self.assertEqual(obtained, expected)

def test_xml_pubmed_publication_type_maps_case_report(self):
expected = (
'<Article>'
'<PublicationType>Case Reports</PublicationType>'
'</Article>'
)
xml_pubmed = ET.fromstring(
'<Article/>'
)
xml_tree = ET.fromstring(
'<article xmlns:mml="http://www.w3.org/1998/Math/MathML" '
'xmlns:xlink="http://www.w3.org/1999/xlink" '
'article-type="case-report" dtd-version="1.1" specific-use="sps-1.9" xml:lang="en">'
'</article>'
)

xml_pubmed_publication_type(xml_pubmed, xml_tree)

obtained = ET.tostring(xml_pubmed, encoding="utf-8").decode("utf-8")

self.assertEqual(obtained, expected)

def test_xml_pubmed_publication_type_maps_retraction_and_partial_retraction(self):
for article_type in ("retraction", "partial-retraction"):
with self.subTest(article_type=article_type):
xml_pubmed = ET.fromstring('<Article/>')
xml_tree = ET.fromstring(
'<article xmlns:mml="http://www.w3.org/1998/Math/MathML" '
'xmlns:xlink="http://www.w3.org/1999/xlink" '
f'article-type="{article_type}" dtd-version="1.1" specific-use="sps-1.9" xml:lang="en">'
'</article>'
)

xml_pubmed_publication_type(xml_pubmed, xml_tree)

obtained = ET.tostring(xml_pubmed, encoding="utf-8").decode("utf-8")

self.assertEqual(
obtained,
'<Article><PublicationType>Retraction Notice</PublicationType></Article>',
)

def test_xml_pubmed_publication_type_maps_expression_of_concern(self):
expected = (
'<Article>'
'<PublicationType>Expression of Concern</PublicationType>'
'</Article>'
)
xml_pubmed = ET.fromstring(
'<Article/>'
)
xml_tree = ET.fromstring(
'<article xmlns:mml="http://www.w3.org/1998/Math/MathML" '
'xmlns:xlink="http://www.w3.org/1999/xlink" '
'article-type="expression-of-concern" dtd-version="1.1" specific-use="sps-1.9" xml:lang="en">'
'</article>'
)

xml_pubmed_publication_type(xml_pubmed, xml_tree)

obtained = ET.tostring(xml_pubmed, encoding="utf-8").decode("utf-8")

self.assertEqual(obtained, expected)

def test_xml_pubmed_publication_type_omits_article_type_without_mapping(self):
# "obituary" has no unambiguous PubMed PublicationType equivalent;
# PublicationType is optional in the DTD, so it's omitted rather
# than defaulted to a possibly-wrong value (see issue #1240).
expected = '<Article/>'
xml_pubmed = ET.fromstring(
'<Article/>'
)
xml_tree = ET.fromstring(
'<article xmlns:mml="http://www.w3.org/1998/Math/MathML" '
'xmlns:xlink="http://www.w3.org/1999/xlink" '
'article-type="obituary" dtd-version="1.1" specific-use="sps-1.9" xml:lang="en">'
'</article>'
)

xml_pubmed_publication_type(xml_pubmed, xml_tree)

obtained = ET.tostring(xml_pubmed, encoding="utf-8").decode("utf-8")

self.assertEqual(obtained, expected)

def test_xml_pubmed_publication_type_without_type(self):
expected = (
'<Article/>'
Expand Down