以跨浏览器方式使用 Javascript 的 DOMParser 时,如何检测 XML 解析错误?

新手上路,请多包涵

似乎所有主流浏览器都实现了 DOMParser API,以便可以将 XML 解析为 DOM,然后使用 XPath、getElementsByTagName 等进行查询…

然而,检测解析错误似乎更棘手。 DOMParser.prototype.parseFromString 总是返回有效的 DOM。当发生解析错误时,返回的 DOM 包含一个 <parsererror> 元素,但在各个主流浏览器中略有不同。

示例 JavaScript:

 xmlText = '<root xmlns="http://default" xmlns:other="http://other"><child><otherr:grandchild/></child></root>';
parser = new DOMParser();
dom = parser.parseFromString(xmlText, 'application/xml');
console.log((new XMLSerializer()).serializeToString(dom));

歌剧结果:

DOM 的根是一个 <parsererror> 元素。

 <?xml version="1.0"?><parsererror xmlns="http://www.mozilla.org/newlayout/xml/parsererror.xml">Error<sourcetext>Unknown source</sourcetext></parsererror>

在 Firefox 中的结果:

DOM 的根是一个 <parsererror> 元素。

 <?xml-stylesheet href="chrome://global/locale/intl.css" type="text/css"?>
<parsererror xmlns="http://www.mozilla.org/newlayout/xml/parsererror.xml">XML Parsing Error: prefix not bound to a namespace
Location: http://fiddle.jshell.net/_display/
Line Number 1, Column 64:<sourcetext>&lt;root xmlns="http://default" xmlns:other="http://other"&gt;&lt;child&gt;&lt;otherr:grandchild/&gt;&lt;/child&gt;&lt;/root&gt;
---------------------------------------------------------------^</sourcetext></parsererror>

结果在 Safari 中:

<root> 元素解析正确,但包含一个嵌套的 <parsererror> 与 Opera 和 Firefox 的 <parsererror> 元素不同的命名空间。

 <root xmlns="http://default" xmlns:other="http://other"><parsererror xmlns="http://www.w3.org/1999/xhtml" style="display: block; white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black"><h3>This page contains the following errors:</h3><div style="font-family:monospace;font-size:12px">error on line 1 at column 50: Namespace prefix otherr on grandchild is not defined
</div><h3>Below is a rendering of the page up to the first error.</h3></parsererror><child><otherr:grandchild/></child></root>


我是否缺少一种简单的跨浏览器方法来检测 XML 文档中是否出现解析错误?或者我必须为不同浏览器可能生成的每个可能的 <parsererror> 元素查询 DOM?

原文由 cspotcode 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 567
2 个回答

这是我想出的最好的解决方案。

我尝试解析一个故意为无效 XML 的字符串,并观察生成的 <parsererror> 元素的命名空间。然后,在解析实际的 XML 时,我可以使用 getElementsByTagNameNS 检测同类 <parsererror> 元素并抛出一个 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;
};

请注意,此解决方案不包括 Internet Explorer 所需的特殊外壳。然而,在 IE 中事情要简单得多。 XML 使用 loadXML 方法进行解析,如果解析成功或失败,该方法分别返回 true 或 false。有关示例,请参见 http://www.w3schools.com/xml/xml_parser.asp

原文由 cspotcode 发布,翻译遵循 CC BY-SA 4.0 许可协议

当我第一次来到这里时,我赞成原始答案(通过 cspotcode ),但是,它在 Firefox 中不起作用。由于所生成文档的结构,生成的名称空间始终为“空”。我做了一些研究(检查 这里的 代码)。这个想法是不使用

invalidXml.childNodes[0].namespaceURI

invalidXml.getElementsByTagName("parsererror")[0].namespaceURI

然后按照原始答案中的名称空间选择“parsererror”元素。但是,如果您有一个有效的 XML 文档,其中带有 <parsererror> 标记,并且与浏览器使用的命名空间相同,那么您最终会收到误报。因此,这里有一个启发式方法来检查您的 XML 是否已成功解析:

 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;
}

为什么不在 DOMParser 中实现异常?

在当前上下文中值得一提的有趣的事情:如果您尝试使用 XMLHttpRequest 获取 XML 文件,解析的 DOM 将存储在 responseXML 属性中,或 null 文件内容无效。也不例外,不是 parsererror 或其他特定指标。只是空的。

原文由 Rast 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题