-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
Consider this testcase:
<script>
var div = document.createElementNS("foo", "div");
div.innerHTML = "<body><p></p></body>";
document.documentElement.appendChild(document.createTextNode(new XMLSerializer().serializeToString(div)));
this shows <div xmlns="foo"><p xmlns="http://www.w3.org/1999/xhtml"></p></div> in Safari, Chrome, Firefox. In Edge it shows <div xmlns="foo" />. No idea where the Edge behavior comes from... especially given that this testcase, which per spec should have identical output:
<script>
var div = document.createElementNS("foo", "div");
var r = document.createRange();
r.selectNodeContents(div);
var frag = r.createContextualFragment("<body><p></p></body>");
div.appendChild(frag);
document.documentElement.appendChild(document.createTextNode(new XMLSerializer().serializeToString(div)));
</script>
shows <div xmlns="foo"><p xmlns="http://www.w3.org/1999/xhtml"></p></div> in Edge (and Firefox; it throws in Chrome/Safari).
What does the spec say it should output? We start at https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML and set the context element to the foo|div. Then we invoke https://w3c.github.io/DOM-Parsing/#dfn-concept-parse-fragment. The node document is HTML, so we invoke https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments. The tokenization state is set to "data state" (step 4). We let root be an html|html and put it on the stack of open elements (step 7). The context element is not a template, so step 8 is irrelevant. In step 9 we create a start tag named "div" but don't really do anything with it so far. In step 10, we find that the stack of open elements has only one thing (the html|html|) and hence use our context node to set the insertion mode. In this case that puts us into the "in body" insertion mode in step 16 of https://html.spec.whatwg.org/multipage/syntax.html#reset-the-insertion-mode-appropriately.
Now we run the parser.
When the "body" start tag token is output, we look at https://html.spec.whatwg.org/multipage/syntax.html#tree-construction-dispatcher and see that the adjusted current node is the foo|div (because the stack of open elements only has the html|html on it and the foo|div is our context element). This adjusted current node is not in the HTML namespace, not a MathML or HTML integration point, so we use the "in foreign content" rules. That lands us at https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign and we match the "A start tag whose tag name is one of .... body" case. This says:
If the parser was originally created for the HTML fragment parsing algorithm, then act as described in the "any other start tag" entry below. (fragment case)
So we go to "Any other start tag". The adjusted current node is not MathML or SVG, so we end up doing "Insert a foreign element for the token, in the same namespace as the adjusted current node." This should create a foo|body and insert it, as far as I can tell. Clearly this is NOT what any of the browsers actually do.
Am I just missing something? @hsivonen, @annevk, help!
// cc @nox