Repository navigation
fix(jats): preserve styling in abstracts and footnotes - #4361
Conversation
Parse abstract paragraphs and footnotes into styled inline runs (bold/italic/underline/strike/sub/sup) instead of flattening them to plain text, and emit them via _emit_inline so formatting is preserved in the document. Unstyled content keeps the previous single-item structure. Extends the JATS styling tests and regenerates the affected e2e groundtruth files. Part of docling-project#3583
|
✅ DCO Check Passed Thanks @Kylinny, all your commits are properly signed off. 🎉 |
Merge Protections🟢 All 2 merge protections satisfied — ready to merge. Show 2 satisfied protections🟢 Enforce conventional commitMake sure that we follow https://www.conventionalcommits.org/en/v1.0.0/
🟢 Require two reviewer for test updatesWhen test data is updated, we require two reviewers
|
I, Junyi Yao <j.yao@wustl.edu>, hereby add my Signed-off-by to this commit: a9a0960 Signed-off-by: Junyi Yao <j.yao@wustl.edu>
The docling-core serializers join sibling inline text items with a single space, so splitting a styled run off from adjacent text that had no whitespace in the source XML (e.g. `<italic>in vitro</italic>.` or `CO<sub>2</sub>`) exported spurious spaces (`in vitro .`, `CO 2`). Strip-then-join also destroyed the information of whether a boundary originally had whitespace. Add `_coalesce_no_space_boundaries`, run between whitespace normalization and boundary stripping in `_flattened_inline_runs` (abstracts and footnotes). At each spaceless run boundary it: 1. moves trailing opening punctuation (`(`, `[`, quotes) forward onto the next run; 2. moves leading closing punctuation (`.`, `,`, `)`, ...) backward onto the previous run; 3. fuses the two runs, keeping the non-baseline formatting when exactly one run carries it. Step 3 trades precise formatting scope for text fidelity: `CO2` keeps its subscript on the fused run instead of exporting `CO 2`. Formula runs and runs with different hyperlink targets are never fused. The body-paragraph path (`_emit_inline`) is untouched. Regenerate the three affected groundtruth fixtures; their exported text (modulo styling markers) is now byte-identical to the pre-PR output. Add `test_jats_plain_abstract_styling_keeps_source_spacing` covering italic+period/comma, `CO<sub>2</sub>e`, `(ECM))<sup>-1</sup>`, parens/brackets around styled runs, and ragged source whitespace. Signed-off-by: Junyi Yao <j.yao@wustl.edu>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
- Sort import blocks (I001) in jats_backend.py and test_backend_jats.py. - Mark intentional curly quotes in punctuation constants (RUF001 noqa). - Condense docstrings/comments to bring jats_backend.py back under the 1500-line max-lines guardrail (1496 lines). Signed-off-by: Junyi Yao <j.yao@wustl.edu>
There was a problem hiding this comment.
Thanks @Kylinny for addressing this open topic for JATS articles.
Without entering into a detailed review, I noticed some aspects that you may want to have a look at:
-
The style checks still fail. Please, check the Contributor guidelines and ensure they pass locally before pushing to the remote server, using
uv prek. -
Reading through your inline comments I have the impression that you are implementing a workaround to an existing issue in docling-core: the space management of the inline groups in the serializers. This is an existing issue that is currently being addressed in PR docling-project/docling-core#693 and it involves the
DoclingDocument, not the backend parsers. I would suggest that you stick to the following contract: respect the blank spaces in the inline groups and delegate the proper (markdown) export to docling-core serializers. The serialization will not be optimal at this point, but we will regenerate the ground-truth files once PR docling-project/docling-core#693 is finalized and merged. Please, do not re-implement the emphasis parsing just for the abstract section. Instead, reuse the current implementation for paragraphs. -
Small correction to your statement:
The JATS backend flattened abstract paragraphs and footnotes to plain text via _get_text()...were silently dropped there — while body paragraphs already preserved them since #4029.
The emphasis in paragraphs is actually supported since PR #3726 . The code from this PR should be the basis of your implementation to support styling in abstracts and footnotes.
Address ceberam's review: drop the abstract/footnote-specific emphasis and spacing workaround (_normalize_segments, _coalesce_no_space_boundaries, _flattened_inline_runs) and reuse the paragraph styling implementation from docling-project#3726 instead. - Abstract <p> elements are now walked with _walk_linear at emit time, sharing the body-paragraph code path. - Footnotes use _walk_inline_formula + _strip_segments directly. - Inline-group spacing is delegated to the docling-core serializers per their contract (docling-core#693); no fusing or punctuation movement. - Tests assert raw inline-run content/formatting instead of markdown output. - Ground truths regenerated for the new (temporarily suboptimal) spacing. Signed-off-by: Junyi Yao <j.yao@wustl.edu>
|
Thanks for the detailed review, @ceberam — all points addressed in the latest push (
|
Signed-off-by: Junyi Yao <j.yao@wustl.edu>
21270ae to
c50b37b
Compare
Signed-off-by: Junyi Yao <j.yao@wustl.edu>
Signed-off-by: Junyi Yao <j.yao@wustl.edu>
|
Thanks @ceberam for the detailed review! All four points are addressed:
Also added the missing footnote single-segment test you pointed out. lint-and-type is green. |
Part of #3583 — covers the remaining
Styling (bold, italic, superscript, ...)item.Problem
The JATS backend flattened abstract paragraphs and footnotes to plain text via
_get_text()(which even carries aTODO: apply styling according to child.tag), so<italic>,<bold>,<sub>/<sup>,<underline>and<strike>were silently dropped there — while body paragraphs already preserved them since #3726.Changes
<p>elements are now walked with the paragraph implementation (_walk_linear, from feat(jats/inline-formula): Support emphasis elements and Inline formulas #3726) at emit time, so abstracts share the body-paragraph styling path instead of a parallel one. This covers plain and structured abstracts, including mixed content._add_footnote_group()parses each<fn>with the shared inline walker (_walk_inline_formula+_strip_segments, from feat(jats/inline-formula): Support emphasis elements and Inline formulas #3726), keeping theFOOTNOTElabel on text runs (formulas stayFORMULA).CO 2,*in vitro* .) until docs: add integrations, revamp docs #693 merges; ground truths will be regenerated then.Tests
tests/test_backend_jats.py: plain-abstract styling (italic/bold/nested/sub/sup/underline/strike), structured-abstract styling, footnote styling incl.FOOTNOTElabels, a no-styling structure-preservation test, and inline-run contract tests (no run fusion, no punctuation movement, source whitespace preserved; markdown output deliberately not asserted)..md/.itxt/.jsonforpmc2231364,pntd.0008301,pone.0234687); the other two fixtures are untouched.ruff check/ruff format --checkclean;ty checkshows only the 5 pre-existing warnings;tach checkpasses. (Fulluv prekcould not run locally due to disk constraints on this machine; the individual hooks were verified equivalently.)