Attaching <head> elements with Javascript works with .innerHTML, but not with XML child nodes
There are probably easier ways to do this, but I'm trying something new.
The main point is that I want to have one JS and one jQuery app for every page in my static website. I want to be able to add elements to the body, but also the head. My files:
home.html
<head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> <script src="eco.js"></script> </head>
eco.js
window.addEventListener("load", function() { var ajax = new XMLHttpRequest(); ajax.onload = postdata; ajax.open("GET", ADDRESS, true); ajax.send(); } ); function postdata() { var xml = jQuery.parseXML(this.responseText); $("head").append(xml.querySelector("head").childNodes); }
and common.xml
<head> <link href='eco.css' type='text/css' rel='stylesheet' /> <link href='home.css' type='text/css' rel='stylesheet' /> </head>
However, this does not work (common.xml is requested and retrieved successfully). Chrome dev tools show the xml nodes have been added to the head successfully as well. However, the page does not reflect the changes, especially the CSS is not included. However, if I change
var xml = jQuery.parseXML(this.responseText); $("head").append(xml.querySelector("head").childNodes);
to
$("head").append(this.responseText);
(and fix common.xml to remove unneeded tags) then the page reflects the changes. Can anyone explain what is going on here?
Thank!
source share
jQuery.parseXML()
returns an object XMLDocument
that is a generic XML DOM that is incompatible with the HTML DOM.
When you add child nodes after parsing an XML file in XML format, what you insert are XML elements, not HTML elements. Since the HTML processor only understands HTML elements link
, it does not recognize them when they come from the XML DOM - they become unknown elements and have no intended meaning.
When you add the markup to the responses directly, that markup is interpreted as HTML because you are working directly with the HTML DOM in your page. This allows your link
elements to work as intended by referencing external stylesheets for use with your page.
The following example with an element without a title shows how the element b
differs between HTML and XML using the same techniques in your question. In HTML, it represents text to stand out from a paragraph , with associated default styles. In plain XML, this is just an arbitrary element with no default styles. In Firefox and IE, each element b
also responds correctly to a named CSS selector (note that they use the XHTML namespace even with HTML elements), although IE does not insert the XML element at all, throwing it instead WrongDocumentError
. The included CSS doesn't work very well in Chrome either - presumably because, as with IE, trying to compromise HTML and XML together isn't exactly the right thing to do.
$(function() { var html = '<b>HTML b element</b>'; var xml = '<root><b>XML b element</b></root>'; $('p.html').append(html); var xmlDoc = jQuery.parseXML(xml); $('p.xml').append(xmlDoc.querySelector(':root').childNodes); });
@namespace 'http://www.w3.org/1999/xhtml'; b::before { content: 'Default namespace '; } |b::before { content: 'Non-namespaced '; } /* Any or no namespace */ *|b { color: blue; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> <p class="html"></p> <p class="xml"></p>
Interestingly, if you use xml.querySelector("head").innerHTML
rather than xml.querySelector("head").childNodes
, it works even though the object is Element
not HTMLElement
(i.e. it xml.querySelector("head") instanceof HTMLElement
returns false). According to this new answer from Louis , recent versions of Firefox and Chrome innerHTML
introduced XML serialization of the content of the XML node element, which explains this behavior. However, this feature innerHTML
cannot be relied upon as it is not cross-browser compatible.
Ultimately, your best bet is not to parse your document as XML in the first place; just treat it like a normal HTML snippet by adding directly responseText
as jQuery is capable of handling HTML snippets.
source share