v0.18.13 - Empty non-void HTML elements inside <foreignObject> are serialized as XML self-closing (<div/>)
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 68/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Tranquilla
- Stack tecnologico
- html, node.js
- Ambito
- web-dev
Direzione di ricerca
Inizia con la riproduzione fornita di parseHTML e segui document.body.innerHTML attraverso la serializzazione, concentrandoti sulla gestione dei namespace in foreignObject. Verifica che gli elementi HTML non-void utilizzino tag di chiusura espliciti, mentre gli elementi HTML void elencati possano usare il self-closing, quindi verifica che il risultato serializzato superi il round-trip senza inghiottire il contenuto degli elementi fratelli.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Empty non-void HTML elements inside <foreignObject> are serialized as XML self-closing (<div/>), producing invalid HTML that swallows following content
Summary
When an empty HTML element (e.g. <div>, <p>, <span>) appears inside an SVG <foreignObject>, parseHTML(...).document.toString() / .innerHTML serializes it using XML self-closing syntax (<div/>) instead of an explicit start/end tag pair (<div></div>).
Per the HTML standard, the self-closing slash is ignored on non-void HTML elements, so <div/> is parsed as an open <div>. Because <foreignObject> is an HTML integration point (its subtree is parsed as HTML, not SVG), this output is invalid: when a spec-compliant HTML parser (i.e. any browser) re-parses it, the unclosed <div> swallows every following sibling — the rest of the <foreignObject>, the rest of the <svg>, and all content after it.
The result is that a serialized document round-tripped through linkedom renders blank / severely mis-nested in a browser.
Environment
- linkedom: 0.18.13
- Node: v22.16.0
Minimal reproduction
const { parseHTML } = require('linkedom');
const input = '<svg><foreignObject><div></div></foreignObject></svg>';
const { document } = parseHTML('<!DOCTYPE html><html><body>' + input + '</body></html>');
console.log(document.body.innerHTML);
Actual output
<svg><foreignobject><div /></foreignobject></svg>
Expected output
<svg><foreignObject><div></div></foreignObject></svg>
<div> is a non-void HTML element and must be serialized as <div></div>. (foreignObject should also retain its camelCase — see note below.)
Scope / characterization
Only empty non-void elements in an SVG/foreignObject context are affected:
| Input | Output | Correct? |
|---|---|---|
<svg><foreignObject><div></div></foreignObject></svg> |
<div /> |
❌ self-closed |
<svg><foreignObject><p></p></foreignObject></svg> |
<p /> |
❌ self-closed |
<svg><foreignObject><div>hi</div></foreignObject></svg> |
<div>hi</div> |
✅ (non-empty) |
<div></div> (plain HTML) |
<div></div> |
✅ (outside SVG) |
So the trigger is: an empty element serialized while it is (incorrectly) treated as being in the XML/SVG namespace, even though <foreignObject> switches its subtree back to the HTML namespace.
Why it matters
<div/> is not equivalent to <div></div> in HTML. Given sibling content:
parseHTML('<!DOCTYPE html><body><svg><foreignObject><div></div><span>X</span></foreignObject></svg>')
.document.body.innerHTML
// => <svg><foreignobject><div /><span>X</span></foreignobject></svg>
linkedom keeps <span> as a sibling internally, but the emitted string is not round-trippable: a browser parsing <div /><span>X</span> inside a foreignObject nests <span> (and everything after) inside the <div>. Real-world impact: serializing a captured page that contains an inline SVG icon built with <foreignObject><div .../></foreignObject> (common on e.g. google.com) makes the whole page render blank.
Suggested fix
Elements inside a <foreignObject> are in the HTML namespace and should follow HTML serialization rules: only the HTML void elements (area, base, br, col, embed, hr, img, input, link, meta, param, source, track, wbr) may be self-closed; all other elements must be serialized with an explicit end tag.
- Lingua principale
- HTML
- Stelle
- 2.1k
- Fork
- 104
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di WebReflection/linkedom
-
`el.style.property = ''` and `e.style.setProperty('property', '')` should delete the property Aperta
Difficoltà 3/5 1-2 giorni Idoneità per principianti 52/100
WebReflection/linkedom#327 · 1 commento ·
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 48/100
WebReflection/linkedom#326 · 5 commenti ·
-
Build Apps For AI Agent. Aperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 15/100
WebReflection/linkedom#321 · 1 commento ·
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 25/100
WebReflection/linkedom#318 · 6 commenti ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
WebReflection/linkedom#317 · 2 reazioni ·
Tutte le issue di WebReflection/linkedom
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
WGBH-MLA/dream-aapb#69 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
simonsobs/tileviewer#114 ·
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
epam/statgpt-admin-frontend#277 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100