Skip to content

fix(xml): keep a part whose text carries a bare ampersand - #158

Open
vaibhavdabas16 wants to merge 1 commit into
firecrawl:mainfrom
vaibhavdabas16:fix/epub-dangling-ampersand
Open

fix(xml): keep a part whose text carries a bare ampersand#158
vaibhavdabas16 wants to merge 1 commit into
firecrawl:mainfrom
vaibhavdabas16:fix/epub-dangling-ampersand

Conversation

@vaibhavdabas16

@vaibhavdabas16 vaibhavdabas16 commented Sep 2, 2026

Copy link
Copy Markdown

Fixes #127.

What happens

An & that begins no reference is not well-formed XML, but real XHTML carries it constantly — Tom & Jerry, R&D, 50% & rising. quick-xml scans forward for the missing ;, runs to end of input, and fails the read, so one stray character rejects the whole part.

In EPUB the loss is silent. Chapters load through optional_xml_part, which logs and skips a part that will not parse, so a title page containing an ampersand disappears and the book appears to begin at the next chapter — exactly the report in #127. The reporter guessed at the punctuation; the character that actually does it is &.

The same stray ampersand fails a required part outright in the OOXML and ODF paths, so this is not EPUB-only.

Repro

title.xhtml:  <html xmlns="..."><body><p>Tom & Jerry (1940)</p></body></html>
ch1.xhtml:    <html xmlns="..."><body><p>chapter one</p></body></html>

Before: chapter one
After: Tom & Jerry (1940)chapter one

The change

One line: enable quick-xml's allow_dangling_amp, next to the check_end_names leniency already set in parse_xml. A dangling ampersand stays literal text; well-formed references still arrive as GeneralRef and resolve through resolve_entity unchanged.

This fits what the parser already does — it recovers from mismatched and unclosed end tags rather than discarding the document — and what resolve_entity already does with an unknown entity name, which is to leave it as literal text.

Tests

  • dangling_ampersand_stays_literal_text — four shapes, including a trailing & at end of input, each keeping the content that follows.
  • well_formed_references_still_resolve_beside_a_dangling_one&amp;, &#65; and &nbsp; still expand with a bare & in the same run.
  • a_title_page_with_a_bare_ampersand_is_still_read — the EPUB conversion missing title page #127 symptom at the EPUB level.

All three fail on main and pass here. Full suite green (299 tests, no snapshot changes), cargo fmt --check and cargo clippy --workspace --all-targets --all-features -D warnings clean.

Note, not addressed here

A raw < in text (<h1>a < b</h1>) still truncates the rest of the element — quick-xml reads it as the start of a tag. Telling a stray < from a real one is a different and much less contained problem, so I left it out rather than widen this change. Happy to open a separate issue if that is worth tracking.


Summary by cubic

Fixes #127 by preserving XML/XHTML parts containing a bare & instead of rejecting the entire part. The ampersand remains literal text, so EPUB title pages are not skipped, while valid entity references continue to resolve normally.

  • Applies to the shared XML parser used by EPUB, OOXML, and ODF inputs.
  • Adds coverage for embedded, trailing, and mixed valid and invalid references.
  • Adds an EPUB regression test confirming content before the next chapter remains readable.

Written for commit ca9fdc8. Summary will update on new commits.

Review in cubic

An `&` that starts no reference is not well-formed XML, but real XHTML
carries it constantly ("Tom & Jerry", "R&D", "50% & rising"). quick-xml
scans forward for the missing `;` to end of input and then fails the
read, so the whole part was rejected over one character.

For EPUB that loss was silent: chapters load through
`optional_xml_part`, so an unparseable title page was logged and
skipped, and the book appeared to begin at the next chapter (firecrawl#127). The
same stray ampersand fails a required part outright in the OOXML and
ODF paths.

Enable quick-xml's `allow_dangling_amp`, alongside the `check_end_names`
leniency already set here. A dangling ampersand stays literal text;
well-formed references still arrive as `GeneralRef` and resolve as
before.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 2 files

Re-trigger cubic

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.

EPUB conversion missing title page

1 participant