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.
This commit is contained in:
Andreas Kling 2026-04-05 22:59:57 +02:00 committed by Shannon Booth
parent a2e735b94c
commit a5dd857380
3 changed files with 14 additions and 10 deletions

View file

@ -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<DocumentType>();

View file

@ -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);

View file

@ -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