Я использую SimpleXML для загрузки в некоторые XML-файлы (которые я не писал / не предоставлял и не мог изменить формат).
Иногда (например, один или два файла из каждых 50 или около того) они не избегают каких-либо специальных символов (в основном, а иногда и других случайных недопустимых вещей). Это создает и выдает, потому что SimpleXML с php просто терпит неудачу, и я действительно не знаю, какой хороший способ обработать разбор неправильного XML.
Моя первая идея состояла в том, чтобы предварительно обработать XML как строку и поместить ВСЕ поля в качестве CDATA, чтобы она работала, но по какой-то нечестивой причине XML, который мне нужно обработать, помещает все свои данные в поля атрибутов. Таким образом, я не могу использовать идею CDATA. Пример XML:
<Author v="By Someone & Someone" />
Каков наилучший способ обработать это, чтобы заменить все недопустимые символы из XML, прежде чем загружать его с помощью SimpleXML?
Вам нужно что-то, что будет использовать внутренние ошибки libxml, чтобы найти недопустимые символы и избежать их соответственно. Вот макет, как я его напишу. Взгляните на результат libxml_get_errors()
для информации об ошибке.
function load_invalid_xml($xml) { $use_internal_errors = libxml_use_internal_errors(true); libxml_clear_errors(true); $sxe = simplexml_load_string($xml); if ($sxe) { return $sxe; } $fixed_xml = ''; $last_pos = 0; foreach (libxml_get_errors() as $error) { // $pos is the position of the faulty character, // you have to compute it yourself $pos = compute_position($error->line, $error->column); $fixed_xml .= substr($xml, $last_pos, $pos - $last_pos) . htmlspecialchars($xml[$pos]); $last_pos = $pos + 1; } $fixed_xml .= substr($xml, $last_pos); libxml_use_internal_errors($use_internal_errors); return simplexml_load_string($fixed_xml); }
Я думаю, что workaroung для создания функции compute_position будет делать строку xml плоской перед обработкой. Перепишите код, отправленный Джошем:
function load_invalid_xml($xml) { $use_internal_errors = libxml_use_internal_errors(true); libxml_clear_errors(true); $sxe = simplexml_load_string($xml); if ($sxe) { return $sxe; } $fixed_xml = ''; $last_pos = 0; // make string flat $xml = str_replace(array("\r\n", "\r", "\n"), "", $xml); // get file encoding $encoding = mb_detect_encoding($xml); foreach (libxml_get_errors() as $error) { $pos = $error->column; $invalid_char = mb_substr($xml, $pos, 1, $encoding); $fixed_xml .= substr($xml, $last_pos, $pos - $last_pos) . htmlspecialchars($invalid_char); $last_pos = $pos + 1; } $fixed_xml .= substr($xml, $last_pos); libxml_use_internal_errors($use_internal_errors); return simplexml_load_string($fixed_xml); }
Я добавил материал для кодирования, потому что у меня были проблемы с простым методом [index] для получения символа из строки.
Это все должно работать, но не знаю, почему, я видел, что столбец $ error-> дает мне другое число, чем нужно. Пытаясь отладить это, просто добавьте некоторые недопустимые символы внутри xml и проверьте, какое значение оно вернет, но не повезло с ним. Надеюсь, кто-то может сказать мне, что не так с этим подходом.