2012-07-19 9 views
22

Es scheint, dass alle gängigen Browser den DOMParser API implementieren, so dass XML in einen DOM analysiert werden und abgefragt dann mit XPath, getElementsByTagName, etc ...Wie erkenne ich XML-Parsing-Fehler bei der Verwendung von Javascript DOMParser in einem Browser-Browser?

Allerdings scheint Erkennung Parsingfehler kniffliger zu sein. DOMParser.prototype.parseFromString gibt immer ein gültiges DOM zurück. Wenn ein Parsing-Fehler auftritt, enthält das zurückgegebene DOM ein <parsererror> Element, aber es unterscheidet sich in jedem Haupt-Browser geringfügig.

Beispiel JavaScript:

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

Ergebnis in Opera:

DOM Wurzel ist ein <parsererror> Element.

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

Ergebnis in Firefox:

Wurzel des DOM ist ein <parsererror> Element.

<?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> 

Ergebnis in Safari:

Das <root> Element analysiert korrekt aber enthält eine verschachtelte <parsererror> in einem anderen Namespace als Opera und <parsererror> Elements Firefox.

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

Fehle ich eine einfache, Cross-Browser-Art und Weise, wenn eine Analyse des Erfassens Fehler irgendwo im Dokument XML aufgetreten? Oder muss ich das DOM für jedes der möglichen <parsererror> Elemente abfragen, die verschiedene Browser erzeugen könnten?

+0

Können Sie '.getElementsByTagName (" parseerror ")' auf dem Stamm-DOM-Knoten aufrufen und davon ausgehen, dass ein Fehler aufgetreten ist, wenn die Länge der zurückgegebenen Knotenliste größer als Null ist? – Pointy

+3

Technisch gesehen könnte das XML-Dokument, das ich analysiere, '' Elemente enthalten, aber immer noch vollständig gültiges XML sein (Elemente würden aus einem anderen Namensraum sein) Also müsste ich mehrere Aufrufe an' .getElementsByTagNameNS (Namespace, 'parser error ') 'für die' Namespace'-URIs von jedem Browser. – cspotcode

+0

Hmm. Nun, die HTML5-Spezifikation dafür ist gelinde gesagt fragmentarisch. – Pointy

Antwort

13

Dies ist die beste Lösung, die ich mir ausgedacht habe.

Ich versuche, eine Zeichenfolge zu analysieren, die absichtlich ungültig XML ist, und beobachten Sie den Namespace des resultierenden Elements <parsererror>. Dann, wenn ich tatsächliches XML analysiere, kann ich getElementsByTagNameNS verwenden, um dieselbe Art von <parsererror> Element zu entdecken und Javascript Error zu werfen.

// 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, 'text/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('<', 'text/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; 
}; 

Beachten Sie, dass diese Lösung nicht das spezielle Gehäuse enthält, das für Internet Explorer benötigt wird. Im IE sind die Dinge jedoch viel einfacher. XML wird mit einer loadXML-Methode analysiert, die wahr oder falsch zurückgibt, wenn das Parsen erfolgreich war oder fehlgeschlagen ist. Ein Beispiel finden Sie in http://www.w3schools.com/xml/xml_parser.asp.

+0

Ich bekomme Folgendes mit dieser und Rast-Funktion unten: TypeError: Kann Eigenschaft 'namespaceURI' von undefined nicht lesen –

9

Als ich das erste Mal hierher kam, habe ich die ursprüngliche Antwort (von cspotcode) upvoted, aber es funktioniert nicht in Firefox. Der resultierende Namespace ist aufgrund der Struktur des erstellten Dokuments immer "Null". Ich machte ein wenig Nachforschungen (überprüfen Sie den Code here).Die Idee ist nicht

invalidXml.childNodes[0].namespaceURI 

aber

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

zu verwenden und wählen Sie dann "ParserError" Element von Namensraum wie in Original Antwort. Wenn Sie jedoch ein gültiges XML-Dokument mit dem Tag <parsererror> in demselben Namespace wie im Browser verwenden, wird ein Fehlalarm ausgegeben. So, hier ist eine Heuristik zu überprüfen, ob Ihre XML erfolgreich analysiert:

function tryParseXML(xmlString) { 
    var parser = new DOMParser(); 
    var parsererrorNS = parser.parseFromString('INVALID', 'text/xml').getElementsByTagName("parsererror")[0].namespaceURI; 
    var dom = parser.parseFromString(xmlString, 'text/xml'); 
    if(dom.getElementsByTagNameNS(parsererrorNS, 'parsererror').length > 0) { 
     throw new Error('Error parsing XML'); 
    } 
    return dom; 
} 

Warum nicht Ausnahmen in DOMParser implementieren?

Interessante Sache wert im aktuellen Kontext zu erwähnen: wenn Sie versuchen, mit XMLHttpRequest XML-Datei zu erhalten, analysierte DOM wird in responseXML Eigenschaft gespeichert werden, oder null, wenn XML-Datei Inhalt ungültig ist. Keine Ausnahme, nicht parsererror oder ein anderer spezifischer Indikator. Nur Null.

+1

PhantomJS benötigt spezielle Behandlung. Ich habe versucht, das bei der Bearbeitung der ersten Antwort zu berücksichtigen. – cburgmer

Verwandte Themen