Исправить некорректный XML в PHP перед обработкой с использованием функций DOMDocument - PullRequest
7 голосов
/ 14 февраля 2010

Мне нужно загрузить XML-документ в PHP, полученный из внешнего источника. XML не объявляет свою кодировку и содержит недопустимые символы, такие как &. Если я пытаюсь загрузить XML-документ непосредственно в браузере, я получаю сообщения об ошибках типа «Недопустимый символ в текстовом содержимом», а также при загрузке файла в PHP я получаю множество предупреждений, таких как: xmlParseEntityRef: no name in Entity и Input is not proper UTF-8, indicate encoding ! Bytes: 0x9C 0x31 0x21 0x3C.

Понятно, что XML не правильно сформирован и содержит недопустимые символы, которые должны быть преобразованы в объекты XML.

Это потому, что канал XML состоит из данных, предоставленных множеством других пользователей, и, очевидно, он не проверяется и не переформатируется до того, как я его получу.

Я разговаривал с поставщиком канала XML, и они говорят, что пытаются заставить поставщиков контента разобраться с этим, но это кажется глупым, поскольку они должны сначала проверить ввод.

Мне в основном нужно исправить XML, исправляя все ошибки кодирования и преобразовывая любые недопустимые символы в сущности XML, чтобы XML загружал проблему при использовании функций PHP DOMDocument.

Мой код в настоящее время выглядит так:

  $feedURL = '3704017_14022010_050004.xml';
  $dom = new DOMDocument();
  $dom->load($feedURL);

Пример XML-файла, показывающего проблему кодировки (нажмите для загрузки): feed.xml

Пример XML, который содержит символы, которые не были преобразованы в сущности XML:

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

Ответы [ 3 ]

11 голосов
/ 14 февраля 2012

Чтобы решить эту проблему, установите для свойства DomDocument recovery значение TRUE до загрузки XML-документа

$dom->recover = TRUE;

Попробуйте этот код:

$feedURL = '3704017_14022010_050004.xml';
$dom = new DOMDocument();
$dom->recover = TRUE;
$dom->load($feedURL);
8 голосов
/ 15 февраля 2010

Попробуйте использовать библиотеку Tidy, которую можно использовать для очистки плохих HTML и XML http://php.net/manual/en/book.tidy.php

Чистое PHP-решение для исправления XML-кода, например:

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

Было бы что-то вроде этого:

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

Это простой конечный автомат, отмечающий, находимся ли мы в теге или нет, а если нет, то кодируем текст с использованием htmlentities.

Стоит отметить, что это может потребовать много памяти для больших файлов, поэтому вы можете захотеть переписать его как потоковый плагин или препроцессор.

0 голосов
/ 18 сентября 2015

Если расширение tidy недоступно, вы можете рассмотреть htmlpurifier .

...