How do I detect XML parsing errors when using Javascript's DOMParser in a cross-browser way?
This is the best solution I've come up with.
I attempt to parse a string that is intentionally invalid XML and observe the namespace of the resulting <parsererror>
element. Then, when parsing actual XML, I can use getElementsByTagNameNS
to detect the same kind of <parsererror>
element and throw a Javascript Error
.
// My function that parses a string into an XML DOM, throwing an Error if XML parsing fails
function parseXml(xmlString) {
var parser = new DOMParser();
// attempt to parse the passed-in xml
var dom = parser.parseFromString(xmlString, 'application/xml');
if(isParseError(dom)) {
throw new Error('Error parsing XML');
}
return dom;
}
function isParseError(parsedDocument) {
// parser and parsererrorNS could be cached on startup for efficiency
var parser = new DOMParser(),
errorneousParse = parser.parseFromString('<', 'application/xml'),
parsererrorNS = errorneousParse.getElementsByTagName("parsererror")[0].namespaceURI;
if (parsererrorNS === 'http://www.w3.org/1999/xhtml') {
// In PhantomJS the parseerror element doesn't seem to have a special namespace, so we are just guessing here :(
return parsedDocument.getElementsByTagName("parsererror").length > 0;
}
return parsedDocument.getElementsByTagNameNS(parsererrorNS, 'parsererror').length > 0;
};
Note that this solution doesn't include the special-casing needed for Internet Explorer. However, things are much more straightforward in IE. XML is parsed with a loadXML
method which returns true or false if parsing succeeded or failed, respectively. See http://www.w3schools.com/xml/xml_parser.asp for an example.
When I came here the first time, I upvoted original answer (by cspotcode), however, it does not work in Firefox. The resulting namespace is always "null" because of the structure of the produced document. I made a little research (check the code here). The idea is to use not
invalidXml.childNodes[0].namespaceURI
but
invalidXml.getElementsByTagName("parsererror")[0].namespaceURI
And then select "parsererror" element by namespace as in original answer. However, if you have a valid XML document with <parsererror>
tag in same namespace as used by browser, you end up with false alarm.
So, here's a heuristic to check if your XML parsed successfully:
function tryParseXML(xmlString) {
var parser = new DOMParser();
var parsererrorNS = parser.parseFromString('INVALID', 'application/xml').getElementsByTagName("parsererror")[0].namespaceURI;
var dom = parser.parseFromString(xmlString, 'application/xml');
if(dom.getElementsByTagNameNS(parsererrorNS, 'parsererror').length > 0) {
throw new Error('Error parsing XML');
}
return dom;
}
Why not implement exceptions in DOMParser?
Interesting thing worth mentioning in current context: if you try to get XML file with XMLHttpRequest
, parsed DOM will be stored in responseXML
property, or null
, if XML file content was invalid. Not an exception, not parsererror
or another specific indicator. Just null.