Parsing splits one text run into several Text nodes at each character reference (`<p>a & b</p>` gives 3 child nodes)
Maintainer antworten meist innerhalb von 5 Tagen
Bewertung
- Schwierigkeit
- 2/5
- Geschätzter Aufwand
- 1-3 Stunden
- Anfängerfreundlichkeit
- 68/100
- Issue-Typ
- Bug
- Klarheit
- Größtenteils klar
- Aktivitätsstatus
- Aktiv
- Tech-Stack
- html, javascript
Rechercherichtung
Beginne mit dem ontext-Handler in esm/shared/parse-from-string.js, der laut Issue für jeden Parser-Callback einen Text-Knoten anhängt. Vergleiche sein Verhalten mit dem DomHandler von htmlparser2 und füge dann einen Regressionstest für Markup mit Zeichenreferenzen hinzu. Als erledigt gilt die Arbeit, wenn das Parsen des Beispiels einen Text-Knoten mit den Daten "a & b" erzeugt und die bestehende Testabdeckung bei 100 % bleibt.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Parsing <p>a & b</p> gives the <p> three Text nodes ("a ", "&", " b"). The HTML parsing algorithm appends each character to the previous Text node, and jsdom gives one Text node, "a & b". Code that walks childNodes and treats each Text node as one run sees extra runs wherever the source has an entity. normalize() merges them afterwards, but every consumer of parsed output has to know to call it on every subtree, and a spec parser never produces the split in the first place ("insert a character": https://html.spec.whatwg.org/multipage/parsing.html#insert-a-character).
Asks:
- Should the parser merge text into the previous Text node when the previous sibling under the same parent is a Text node, as the HTML parsing algorithm does?
- If yes, I can open a PR that changes
esm/only, with a test, keeping coverage at 100%.
Environment: linkedom 0.18.14 (npm, latest) and main at e2ee208, htmlparser2 10.1.0, Node 24.14.1, macOS.
Test case:
import { DOMParser } from 'linkedom'
const doc = new DOMParser().parseFromString('<!doctype html><html><body><p>a & b</p></body></html>', 'text/html')
const p = doc.querySelector('p')
console.log('textContent:', JSON.stringify(p.textContent))
console.log('childNodes.length:', p.childNodes.length)
console.log('childNodes data:', JSON.stringify([...p.childNodes].map((n) => n.data)))
Output:
textContent: "a & b"
childNodes.length: 3
childNodes data: ["a ","&"," b"]
Expected: childNodes.length: 1, data ["a & b"] (what jsdom 29.1.1 returns for the same markup).
| Input | linkedom Text nodes | jsdom Text nodes |
|---|---|---|
<p>a and b</p> |
1 | 1 |
<p>a & b</p> |
3 | 1 |
<p>x < y > z ©</p> |
6 | 1 |
parseHTML gives the same result as DOMParser (3 nodes for <p>a & b</p>).
Raw output (npm 0.18.14, main e2ee208, variants, htmlparser2)
$ node repro.mjs # linkedom 0.18.14 from npm
textContent: "a & b"
childNodes.length: 3
childNodes data: ["a ","&"," b"]
$ node repro-main.mjs # main e2ee208 esm/
textContent: "a & b"
childNodes.length: 3
childNodes data: ["a ","&"," b"]
$ node variants.mjs
no entity: 1 ["a and b"]
&: 3 ["a ","&"," b"]
< > ©: 6 ["x ","<"," y ",">"," z ","©"]
parseHTML: 3
$ node htmlparser2-ontext.mjs # htmlparser2 10.1.0, decodeEntities: true
htmlparser2 ontext calls: ["a ","&"," b"]
$ node jsdom-control.mjs
jsdom childNodes.length: 1 ["a & b"]
Where it comes from: htmlparser2 with decodeEntities: true calls ontext once per piece around each character reference. The ontext handler in parseFromString appends a new Text node for every call:
htmlparser2's own DomHandler merges each ontext piece into the previous Text node (domhandler 5.0.3, lib/index.js, ontext), so with the same callbacks it yields one node for <p>a & b</p>.
No existing issue found for this; the closest are #62 and #71, which are about serializing entities, not the node split.
- Vorherrschende Sprache
- HTML
- Sterne
- 2.1k
- Forks
- 117
- Ø Merge
- 4 T. 13 Std.
- Gemergte PRs (30 T.)
- 2
Entwicklungsumgebung
Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus WebReflection/linkedom
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
WebReflection/linkedom#365 ·
Maintainer antworten meist innerhalb von 5 Tagen
-
SVG elements in an HTML document report an upper-cased tagName ("PATH" instead of "path")Evtl. vergeben @jonasporto hat das vor 9 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
WebReflection/linkedom#344 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 5 Tagen
-
`TextElement.toString()` puts the element text back at the first `><` of the start tag, so an attribute value containing `><` swallows the text of `<style>`, `<script>`, `<title>` and `<textarea>`Evtl. vergeben @vsolano9 hat das vor 22 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
WebReflection/linkedom#341 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 5 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
WebReflection/linkedom#340 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 5 Tagen
-
Element#matches() compiles the selector on every callEvtl. vergeben @jonasporto hat das vor 22 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 35/100
WebReflection/linkedom#348 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 5 Tagen
Alle Issues in WebReflection/linkedom
Ähnliche Issues
-
`Time.at(t, in: nil)` returns UTC instead of the local time (or the time zone of `t`), unlike CRubyOffen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
Maintainer antworten meist innerhalb von 1 Tag
-
bug implicit-state
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
PecanProject/sipnet#435 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 2 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100