Skip to content
Merged
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
37 changes: 30 additions & 7 deletions packtools/sps/models/v2/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,13 @@ def text(self):
"""
Returns the concatenated text content of the abstract.
- With sections: concatenates title and p from each section
- Without sections: concatenates p elements
- Without sections but with p: concatenates p elements
- Without sections or p (non-SPS-compliant legacy XML, e.g. some
migrated articles): falls back to the node's raw text, excluding
the title
"""
text_parts = []

# Check if abstract has sections by querying the node directly
if self.node.xpath("sec"):
# With sections: include title and p from each section
Expand All @@ -251,13 +254,33 @@ def text(self):
if section.get("p") and section["p"].get("plain_text"):
text_parts.append(section["p"]["plain_text"])
else:
# Without sections: include only p elements
for p_item in self.p:
if p_item.get("plain_text"):
text_parts.append(p_item["plain_text"])

p_items = list(self.p)
if p_items:
# Without sections: include only p elements
for p_item in p_items:
if p_item.get("plain_text"):
text_parts.append(p_item["plain_text"])
else:
# Legacy/non-SPS-compliant abstracts: text sits directly
# under <abstract>/<trans-abstract>, not wrapped in <p>/<sec>
raw_text = self._raw_text_excluding_title
if raw_text:
text_parts.append(raw_text)

return " ".join(text_parts)

@property
def _raw_text_excluding_title(self):
full_text = " ".join(t.strip() for t in self.node.itertext() if t.strip())
title_node = self.node.find("title")
if title_node is not None:
title_text = " ".join(
t.strip() for t in title_node.itertext() if t.strip()
)
if title_text and full_text.startswith(title_text):
full_text = full_text[len(title_text):].strip()
return full_text

@property
def data(self):
if self.lang:
Expand Down
64 changes: 64 additions & 0 deletions tests/sps/models/v2/test_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,70 @@ def test_section_without_paragraph(self):
self.assertEqual(abstract.text, expected)


class AbstractTextWithoutPWrapperTest(TestCase):
"""Regression test for scieloorg/scms-upload#1031: some legacy migrated
XML (e.g. URY collection) has abstract text sitting directly under
<abstract>/<trans-abstract>, not wrapped in <p> or <sec>. packtools
never read this text, so it was silently dropped."""

def test_text_without_p_wrapper(self):
xml = """
<abstract xml:lang="es">
<title>Resumen:</title> Texto do resumo sem tag p.
</abstract>
"""
node = etree.fromstring(xml)
abstract = Abstract(
node, lang="es",
tags_to_keep=None, tags_to_keep_with_content=None,
tags_to_remove_with_content=None, tags_to_convert_to_html=None
)
self.assertEqual(abstract.text, "Texto do resumo sem tag p.")

def test_data_text_value_without_p_wrapper(self):
xml = """
<trans-abstract xml:lang="en">
<title>Abstract:</title> Abstract text without a p tag.
</trans-abstract>
"""
node = etree.fromstring(xml)
abstract = Abstract(
node, lang="en",
tags_to_keep=None, tags_to_keep_with_content=None,
tags_to_remove_with_content=None, tags_to_convert_to_html=None
)
self.assertEqual(abstract.data["text"], "Abstract text without a p tag.")

def test_without_p_wrapper_and_without_title(self):
"""No title to strip, entire node text is the abstract."""
xml = """
<abstract xml:lang="en"> Just loose text, no title, no p.</abstract>
"""
node = etree.fromstring(xml)
abstract = Abstract(
node, lang="en",
tags_to_keep=None, tags_to_keep_with_content=None,
tags_to_remove_with_content=None, tags_to_convert_to_html=None
)
self.assertEqual(abstract.text, "Just loose text, no title, no p.")

def test_only_title_still_returns_empty(self):
"""Existing behavior must be preserved: a title with no further
loose text still yields an empty abstract text."""
xml = """
<abstract xml:lang="en">
<title>Abstract</title>
</abstract>
"""
node = etree.fromstring(xml)
abstract = Abstract(
node, lang="en",
tags_to_keep=None, tags_to_keep_with_content=None,
tags_to_remove_with_content=None, tags_to_convert_to_html=None
)
self.assertEqual(abstract.text, "")


class AbstractTextLanguageTest(TestCase):
"""Test the text property with different languages"""

Expand Down