Fixieren Sie missgebildete XML in PHP vor der Verarbeitung mithilfe von Domdocument -Funktionen
-
20-09-2019 - |
Frage
Ich muss ein XML -Dokument in PHP laden, das von einer externen Quelle stammt. Der XML erklärt nicht, dass es sich um Codierung handelt und enthält illegale Charaktere wie &
. Wenn ich versuche, das XML -Dokument direkt im Browser zu laden, erhalte ich Fehler wie "Ein ungültiges Zeichen wurde im Textinhalt gefunden". Auch wenn die Datei in PHP geladen wird, erhalte ich viele Warnungen wie: xmlParseEntityRef: no name in Entity
und Input is not proper UTF-8, indicate encoding ! Bytes: 0x9C 0x31 0x21 0x3C
.
Es ist klar, dass die XML nicht gut geformt ist und illegale Zeichen enthält, die in XML -Entitäten konvertiert werden sollten.
Dies liegt daran, dass der XML -Feed aus Daten besteht, die von vielen anderen Benutzern geliefert wurden und eindeutig nicht validiert oder neu formatiert wird, bevor ich sie bekomme.
Ich habe mit dem Lieferanten des XML -Feeds gesprochen und sie sagen, dass sie versuchen, die Inhaltsanbieter dazu zu bringen, dies zu klären, aber dies scheint albern, da sie zuerst die Eingabe validieren sollten.
Grundsätzlich muss ich die XML -Korrektur von Codierungsfehlern beheben und illegale Zeichen in XML -Entitäten konvertieren, sodass das XML -Problem bei der Verwendung von PHP -Domdocument -Funktionen Probleme lädt.
Mein Code sieht derzeit aus:
$feedURL = '3704017_14022010_050004.xml';
$dom = new DOMDocument();
$dom->load($feedURL);
Beispiel XML -Datei mit Codierungsproblemen (klicken Sie zum Herunterladen): feed.xml
Beispiel XML, das Zeichen enthält, die nicht in XML -Entitäten konvertiert wurden:
<?xml version="1.0"?>
<feed>
<RECORD>
<ID>117387</ID>
<ADVERTISERNAME>Test</ADVERTISERNAME>
<AID>10544740</AID>
<NAME>This & This</NAME>
<DESCRIPTION>For one day only this is > than this.</DESCRIPTION>
</RECORD>
</feed>
Lösung
Versuchen Sie, die Tidy -Bibliothek zu verwenden, mit der schlechtes HTML und XML gereinigt werden könnenhttp://php.net/manual/en/book.tidy.php
Eine reine PHP -Lösung, um einige XML wie folgt zu beheben:
<?xml version="1.0"?>
<feed>
<RECORD>
<ID>117387</ID>
<ADVERTISERNAME>Test < texter</ADVERTISERNAME>
<AID>10544740</AID>
<NAME>This & This</NAME>
<DESCRIPTION>For one day only this is > than this.</DESCRIPTION>
</RECORD>
</feed>
Wäre so etwas:
function cleanupXML($xml) {
$xmlOut = '';
$inTag = false;
$xmlLen = strlen($xml);
for($i=0; $i < $xmlLen; ++$i) {
$char = $xml[$i];
// $nextChar = $xml[$i+1];
switch ($char) {
case '<':
if (!$inTag) {
// Seek forward for the next tag boundry
for($j = $i+1; $j < $xmlLen; ++$j) {
$nextChar = $xml[$j];
switch($nextChar) {
case '<': // Means a < in text
$char = htmlentities($char);
break 2;
case '>': // Means we are in a tag
$inTag = true;
break 2;
}
}
} else {
$char = htmlentities($char);
}
break;
case '>':
if (!$inTag) { // No need to seek ahead here
$char = htmlentities($char);
} else {
$inTag = false;
}
break;
default:
if (!$inTag) {
$char = htmlentities($char);
}
break;
}
$xmlOut .= $char;
}
return $xmlOut;
}
Dies ist eine einfache Zustandsmaschine, die feststellt, ob wir uns in einem Tag befinden oder nicht, und wenn nicht, codieren Sie den Text mithilfe von HTMLEnten.
Es ist erwähnenswert, dass dies auf große Dateien hungrig sein wird, sodass Sie es möglicherweise als Stream-Plugin oder Pre-Processor neu schreiben möchten.
Andere Tipps
Um dieses Problem zu lösen, setzen Sie die Domdocument Recovering Eigenschaft zu TRUE
Vor dem Laden des XML -Dokuments
$dom->recover = TRUE;
Probieren Sie diesen Code aus:
$feedURL = '3704017_14022010_050004.xml';
$dom = new DOMDocument();
$dom->recover = TRUE;
$dom->load($feedURL);
Wenn die ordentliche Erweiterung keine Option ist, können Sie dies in Betracht ziehen htmlpurifier.