This component may be obtained, modified and distributed free of charge for personal as well as commercial use. Please see the license for the complete terms and exact wording.
(2006-05-29) Changed license to Apache Software License 2.0.
The usage of XML is everywhere. The usage of XML inside the browser has been around for a while but not until lately has it been possible to get this to work in a satisfactory way in more than one browser. A while back Mozilla added support for creating MS compatible XML classes scriptable from JavaScript.
This script creates a common interface for Mozilla and IE and also extends the Mozilla classes a little to make them behave even more like the Microsoft interfaces.
In IE there are two useful ActiveX objects that are marked as safe for scripting. These objects use the MSXML XML parser and are created like this:
var xmlDocument = new ActiveXObject("MsXml2.XmlDom"); var xmlHttp = new ActiveXObject("MsXml2.XmlHttp");
The first object is an XML document that allows you to add new nodes to, using standard DOM1 Core methods. There are also a few extra methods provided by this object that allows you to load (get) an XML document from a file or from a string.
The second of these objects allows you to post an XML document to the server and the reply from the server is sent back to the XML HTTP request object. This allows you to post XML data to the server without leaving the current page.
Mozilla uses W3C compatible technologies whenever there
is one. In the case of creating an XML document there happens to be a standard way to do
this that was
introduced in DOM Level 2.
This uses the createDocument
method of the DOMImplementation
interface.
document.implementation.createDocument(sNameSpaceUri, sQualifiedName, oDoctype); // in the simplest case it can be used as below document.implementation.createDocument("", "", null);
This creates an XmlDocument
and one can use any DOM (level 1, 2 and 3)
methods supported by Mozilla. Mozilla also decided to add the method load
that allows you to load an XML document from a file (to be compatible with MS).
Mozilla also has support for XML http request objects. In this case Mozilla tried to implement as much as possible of the MS equivalent object but since this is not part of any W3C standard a special JS contructor is provided. Below is the code to create an XML http request object.
new XMLHttpRequest();
The implementation creates two factory classes, called XmlDocument
and XmlHttp
. Both these classes have a static method (class method,
shared method) called create
that creates an instance object of the
right type.
var xmlDoc = XmlDocument.create(); var xmlHttp = XmlHttp.create();
// XmlHttp factory function XmlHttp() {} XmlHttp.create = function () { try { if (window.XMLHttpRequest) { var req = new XMLHttpRequest(); // some older versions of Moz did not support the readyState property // and the onreadystate event so we patch it! if (req.readyState == null) { req.readyState = 1; req.addEventListener("load", function () { req.readyState = 4; if (typeof req.onreadystatechange == "function") req.onreadystatechange(); }, false); } return req; } if (window.ActiveXObject) { return new ActiveXObject(getControlPrefix() + ".XmlHttp"); } } catch (ex) {} // fell through throw new Error("Your browser does not support XmlHttp objects"); };
If one removes the extra handling of the onreadystate
event for Mozilla
the static method create
just checks the support of the browser and uses
the supported mechanism to create an instance of the desired object. If the current
version of Mozilla does not support the readyState
property we know that it
does not support the onreadystate
event so we listen to the onload
event and once that occurs we call the custom event handler (if provided).
// XmlDocument factory function XmlDocument() {} XmlDocument.create = function () { try { // DOM2 if (document.implementation && document.implementation.createDocument) { var doc = document.implementation.createDocument("", "", null); // some versions of Moz do not support the readyState property // and the onreadystate event so we patch it! if (doc.readyState == null) { doc.readyState = 1; doc.addEventListener("load", function () { doc.readyState = 4; if (typeof doc.onreadystatechange == "function") doc.onreadystatechange(); }, false); } return doc; } if (window.ActiveXObject) return new ActiveXObject(getControlPrefix() + ".XmlDom"); } catch (ex) {} throw new Error("Your browser does not support XmlDocument objects"); };
In this case the same extra handling to support onreadystatechange
is added but except for this the create
method should be fairly straight
forward.
Different versions of IE and Windows has different version of the MSXML parser installed
and therefore we have created a litte helper function that checks which control prefix works
in the user's version of IE. This function tries to create both the "XmlHttp"
and "XmlDom"
ActiveX objects and once it finds a prefix that works it stores that
so that it does not have to try that again. If no valid control prefix is found an exception is
thrown. The version independent control prefix is "MSXML2" and that is what is tried first.
After that a few other prefixes are tested.
function getControlPrefix() { if (getControlPrefix.prefix) return getControlPrefix.prefix; var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"]; var o, o2; for (var i = 0; i < prefixes.length; i++) { try { // try to create the objects o = new ActiveXObject(prefixes[i] + ".XmlHttp"); o2 = new ActiveXObject(prefixes[i] + ".XmlDom"); return getControlPrefix.prefix = prefixes[i]; } catch (ex) {}; } throw new Error("Could not find an installed XML parser"); }
For a general article about extending the Mozilla DOM see the IE Emu articles.
We would like to be able to use the loadXML
method on the XmlDocument
that takes a string and parses that as XML. The Mozilla version of XmlDocument
does not
support that natively so we extend the prototype of the Document
to support this. To
parse an XML string in Mozilla one can use the built in DOMParser
object.
To load the document with an XML string we first parse the string and after that we remove all the nodes of the original tree and inserts all of the nodes from the document we got from the parsed string.
Document.prototype.loadXML = function (s) { // parse the string to a new doc var doc2 = (new DOMParser()).parseFromString(s, "text/xml"); // remove all initial children while (this.hasChildNodes()) this.removeChild(this.lastChild); // insert and import nodes for (var i = 0; i < doc2.childNodes.length; i++) { this.appendChild(this.importNode(doc2.childNodes[i], true)); } };
There is one more important feature that the Mozilla native version of the XML document is
missing and that is a a way to serialize the DOM tree to an XML string. Fortunately the Mozilla
developers have realized this and provided a class that can do this easily (even if creating a
serializer using JS is fairly easy). This is done by using a class called
XMLSerializer
. In IE the XML document has a property called
xml
that returns the DOM tree serialized to an XML string so we define a setter
on the Document.prototype
that returns this.
Document.prototype.__defineGetter__("xml", function () { return (new XMLSerializer()).serializeToString(this); });
The best documentation for the XmlDocument is probably the W3C DOM level 1, 2 and 3 but MS has an easier to read documentation at MSDN. Mozilla.org has a project page covering the extra XML features it provides.