36 Stimmen

XML-Parserfehler: Entität nicht definiert

Ich habe auf Stackoverflow nach diesem Problem gesucht und ein paar Themen gefunden, aber ich habe das Gefühl, dass es für mich keine wirklich klare Antwort gibt.

Ich habe ein Formular, das Benutzer ausfüllen und dessen Wert in einer XML-Datei speichern. Die XML ist auf UTF-8 codiert.

Ab und zu kopiert ein Benutzer Text aus irgendeiner Quelle und das ist, wenn ich den Fehler "Entität nicht definiert" bekomme.

Ich erkenne, dass XML nur eine Auswahl von Entitäten unterstützt und alles darüber hinaus nicht erkannt wird - daher der Parserfehler.

Nach meinem Verständnis gibt es einige Optionen, die ich gesehen habe:

  1. Ich kann alle finden und durch oder ein tatsächliches Leerzeichen ersetzen.
  2. Ich kann den betreffenden Code in einen CDATA-Bereich setzen.
  3. Ich kann diese Entitäten in die XML-Datei aufnehmen.

Was ich mit der XML-Datei mache, ist, dass der Benutzer Inhalte in ein Formular eingeben kann, es in einer XML-Datei gespeichert wird und dieser Inhalt dann als XHTML auf einer Webseite angezeigt wird (geparst mit SimpleXML).

Von den drei Optionen oder anderen Optionen, von denen ich nichts weiß, was ist wirklich der beste Weg, um mit diesen Entitäten umzugehen?

Vielen Dank, Ryan

UPDATE

Ich möchte mich bei allen für das großartige Feedback bedanken. Tatsächlich habe ich festgestellt, was meine Entitätsfehler verursacht hat. Alle Vorschläge haben mich dazu gebracht, genauer hinzusehen!

Einige Textfelder waren einfache Textfelder, aber meine Textareas wurden mit TinyMCE verbessert. Es stellte sich heraus, dass die PHP-Warnungen immer auf Daten aus den TinyMCE-verbesserten Textareas verwiesen. Später bemerkte ich auf einem PC, dass alle Zeichen entfernt wurden (weil es sie nicht lesen konnte), aber auf einem MAC konnte man kleine quadratische Kästchen sehen, die auf die Unicode-Nummer dieses Zeichens verwiesen. Der Grund, warum es auf einem MAC überhaupt in Quadraten angezeigt wurde, ist, weil ich utf8_encode verwendet habe, um Daten, die nicht in UTF waren, zu codieren, um andere Parsingfehler zu verhindern (was irgendwie auch mit TinyMCE zusammenhängt).

Die Lösung für all dies war ziemlich einfach:

Ich habe diese Zeile entity_encoding : "utf-8" in meinem tinyMCE.init hinzugefügt. Jetzt werden alle Zeichen so angezeigt, wie sie angezeigt werden sollen.

Das Einzige, was ich nicht verstehe, ist, warum die Zeichen immer noch angezeigt werden, wenn sie in Textfelder eingefügt werden, weil nichts sie in UTF konvertiert, aber mit TinyMCE war das ein Problem.

24voto

Gaurav Arya Punkte 249

Ich stimme zu, dass es sich rein um ein Codierungsproblem handelt. In PHP habe ich das Problem wie folgt gelöst:

  1. Bevor ich das HTML-Fragment dem Konstruktor von SimpleXMLElement übergebe, dekodiere ich es mit html_entity_decode.

  2. Dann wird es weiter codiert mit utf8_encode().

    $headerDoc = '' . utf8_encode(html_entity_decode($headerFragment)) . ''; $xmlHeader = new SimpleXMLElement($headerDoc);

Jetzt wirft der obige Code keine undefinierte Entität-Fehler mehr.

19voto

Tomalak Punkte 320467

Sie könnten den Text in HTML parsen und ihn nur mit den entsprechenden numerischen Entitäten neu entkapseln (z.B.: → ). Auf jeden Fall ist es keine gute Idee, ungesäuberte Benutzereingaben einfach zu verwenden.

In XML sind alle numerischen Entitäten erlaubt, nur die benannten, die man aus HTML kennt, funktionieren nicht (mit Ausnahme von &, ", <, >, ').

Die meiste Zeit jedoch können Sie einfach das tatsächliche Zeichen (öö) in die XML-Datei schreiben, sodass keine Notwendigkeit besteht, eine Entitätsreferenz zu verwenden. Wenn Sie eine DOM-API zum Manipulieren Ihrer XML verwenden (und das sollten Sie!), ist dies Ihre sicherste Wahl.

Schließlich (dies ist die Lösung des faulen Entwicklers) könnten Sie eine fehlerhafte XML-Datei erstellen (d.h. nicht wohlgeformt, mit Entitätsfehlern) und sie einfach durch Tidy schleusen für die notwendigen Korrekturen. Dies kann funktionieren oder fehlschlagen, je nachdem, wie kaputt das Ganze ist. Meiner Erfahrung nach ist Tidy jedoch ziemlich clever und lässt Ihnen trotzdem viel Spielraum.

5voto

LarsH Punkte 26458

1. Ich kann alle [ ?] finden und ersetzen und sie mit [ ?] oder einem echten Leerzeichen austauschen.

Dies ist eine robuste Methode, erfordert jedoch, dass Sie eine Tabelle aller HTML-Entitäten haben (ich gehe davon aus, dass die eingefügten Informationen aus HTML stammen) und den eingefügten Text auf Entitätsreferenzen analysieren.

2. Ich kann den betreffenden Code in einen CDATA-Abschnitt einfügen.

Das heißt, die Analyse für den gesamten Abschnitt deaktivieren? Dann müssten Sie es auf andere Weise analysieren. Könnte funktionieren.

3. Ich kann diese Entitäten in die XML-Datei aufnehmen.

Meinen Sie, die Entitätsdefinitionen einzuschließen? Ich denke, das ist ein einfacher und robuster Weg, wenn es Ihnen nichts ausmacht, die XML-Datei ein wenig größer zu machen. Sie könnten eine "eingeschlossene" Datei haben (eine im Web finden), die eine externe Entität ist, auf die Sie von oben aus Ihrer Haupt-XML-Datei verweisen.

Ein Nachteil ist, dass der XML-Parser, den Sie verwenden, einer sein muss, der externe Entitäten verarbeitet (was nicht alle Parser tun müssen). Und er muss die (möglicherweise relative) URL der externen Entität korrekt auflösen können, damit sie erreichbar ist. Dies ist nicht allzu schlimm, aber es kann die Einschränkungen Ihrer Verarbeitungswerkzeuge erhöhen.

4. Sie könnten Nicht-XML-Inhalte im eingefügten Inhalt verbieten. Unter anderem würde dies Entitätsverweise verbieten, die in XML nicht vordefiniert sind (die 5, die Tomalak erwähnt hat) oder im Inhalt selbst definiert sind. Dies könnte jedoch gegen die Anforderungen der Anwendung verstoßen, wenn Benutzer HTML einfügen können müssen.

5. Sie könnten den eingefügten Inhalt als HTML in einen DOM-Baum analysieren, indem Sie einigeDiv.innerHTML = derEingefügteInhalt; setzen. Mit anderen Worten, erstellen Sie irgendwo ein Div (wahrscheinlich display=none, außer für Debugging). Angenommen, Sie haben dann eine JavaScript-Variable meinDiv, die dieses Div-Element enthält, und eine weitere Variable meinFeld, die das Element enthält, das Ihr Eingabetextfeld ist. Dann machen Sie in JavaScript folgendes:

myDiv.innerHTML = myField.value;

das nimmt den nicht analysierten Text von myField, analysiert ihn in einen HTML-DOM-Baum und fügt ihn als HTML-Inhalt in myDiv ein.

Dann würden Sie eine browserbasierte Methode verwenden, um den DOM-Baum wieder in XML zu serialisieren (= "de-analysieren"). Sehen Sie sich zum Beispiel diese Frage an. Dann senden Sie das Ergebnis als XML an den Server.

Ob Sie diese Fehlerbehebung im Browser oder auf dem Server durchführen möchten (wie @Hannes vorgeschlagen hat), hängt von der Größe der Daten, wie schnell die Antwort sein muss, wie leistungsstark Ihr Server ist und davon ab, ob es Ihnen wichtig ist, ob Hacker absichtlich kein wohlgeformtes XML senden.

3voto

Valeri Punkte 318

Verwenden Sie "htmlentities()" mit Flag "ENT_XML1": htmlentities($value, ENT_XML1);

Wenn Sie die Klasse "SimpleXMLElement" verwenden:

$SimpleXMLElement->addChild($name, htmlentities($value, ENT_XML1));

2voto

Hannes Punkte 7857

Wenn Sie alle Zeichen konvertieren möchten, kann Ihnen dies helfen (ich habe es vor einiger Zeit geschrieben):

http://www.lautr.com/convert-all-applicable-characters-to-numeric-entities-for-use-in-xml

function _convertAlphaEntitysToNumericEntitys($entity) {
  return '&#'.ord(html_entity_decode($entity[0])).';';
}

$content = preg_replace_callback(
  '/&([\w\d]+);/i',
  '_convertAlphaEntitysToNumericEntitys',
  $content);

function _convertAsciOver127toNumericEntitys($entity) {
  if(($asciCode = ord($entity[0])) > 127)
    return '&#'.$asciCode.';';
  else
    return $entity[0];
}

$content = preg_replace_callback(
  '/[^\w\d ]/i',
  '_convertAsciOver127toNumericEntitys', $content);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X