From a5dd857380f3a129e6c8df3e5dc4095a51a6ddf5 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 5 Apr 2026 22:59:57 +0200 Subject: [PATCH] LibWeb: Fix XML processing instruction placement DOM pre-insertion validity allows processing instructions as children of a document. However, Document::is_child_allowed() still rejected them, so XML documents silently dropped valid processing-instruction nodes and produced the wrong sibling relationships. Processing instructions that appear inside a DTD subset are not document children and should not surface in the DOM tree. Ignore those SAX callbacks while libxml is parsing the subset so the XML parser builds the correct document structure. --- Libraries/LibWeb/DOM/Document.cpp | 1 + Libraries/LibXML/Parser/Parser.cpp | 4 ++++ .../wpt-import/dom/nodes/Node-properties.txt | 19 +++++++++---------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index 94a1faa837..75bb4375b5 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -955,6 +955,7 @@ bool Document::is_child_allowed(Node const& node) const case NodeType::TEXT_NODE: return false; case NodeType::COMMENT_NODE: + case NodeType::PROCESSING_INSTRUCTION_NODE: return true; case NodeType::DOCUMENT_TYPE_NODE: return !first_child_of_type(); diff --git a/Libraries/LibXML/Parser/Parser.cpp b/Libraries/LibXML/Parser/Parser.cpp index 498e8f4e94..b82a26db89 100644 --- a/Libraries/LibXML/Parser/Parser.cpp +++ b/Libraries/LibXML/Parser/Parser.cpp @@ -360,6 +360,10 @@ static void processing_instruction_handler(void* ctx, xmlChar const* target, xml if (!context) return; + // Processing instructions inside a DTD subset are not document children. + if (parser_ctx->inSubset != 0) + return; + auto target_str = xml_char_to_byte_string(target); auto data_str = xml_char_to_byte_string(data); diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Node-properties.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Node-properties.txt index f0f46062c8..ae0f8ada0c 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Node-properties.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Node-properties.txt @@ -2,8 +2,7 @@ Harness status: OK Found 726 tests -718 Pass -8 Fail +726 Pass Pass testDiv.nodeType Pass testDiv.ownerDocument Pass testDiv.parentNode @@ -217,11 +216,11 @@ Pass foreignPara2.firstChild Pass foreignPara2.lastChild Pass foreignPara2.hasChildNodes() Pass xmlDoc.nodeType -Fail xmlDoc.childNodes.length +Pass xmlDoc.childNodes.length Pass xmlDoc.childNodes[0] Pass xmlDoc.childNodes[1] -Fail xmlDoc.childNodes[2] -Fail xmlDoc.childNodes[3] +Pass xmlDoc.childNodes[2] +Pass xmlDoc.childNodes[3] Pass xmlDoc.URL Pass xmlDoc.compatMode Pass xmlDoc.characterSet @@ -247,7 +246,7 @@ Pass xmlElement.parentElement Pass xmlElement.childNodes.length Pass xmlElement.childNodes[0] Pass xmlElement.previousSibling -Fail xmlElement.nextSibling +Pass xmlElement.nextSibling Pass xmlElement.textContent Pass xmlElement.namespaceURI Pass xmlElement.prefix @@ -373,10 +372,10 @@ Pass detachedXmlTextNode.firstChild Pass detachedXmlTextNode.hasChildNodes() Pass processingInstruction.nodeType Pass processingInstruction.ownerDocument -Fail processingInstruction.parentNode +Pass processingInstruction.parentNode Pass processingInstruction.parentElement -Fail processingInstruction.previousSibling -Fail processingInstruction.nextSibling +Pass processingInstruction.previousSibling +Pass processingInstruction.nextSibling Pass processingInstruction.nodeValue Pass processingInstruction.target Pass processingInstruction.nodeName @@ -467,7 +466,7 @@ Pass xmlComment.nodeType Pass xmlComment.ownerDocument Pass xmlComment.parentNode Pass xmlComment.parentElement -Fail xmlComment.previousSibling +Pass xmlComment.previousSibling Pass xmlComment.nextSibling Pass xmlComment.nodeValue Pass xmlComment.nodeName