XMLReader (в Php) и обработка ошибок - PullRequest
3 голосов
/ 26 августа 2010

Быстрая версия:

Каков стандартный (инновационный? Любой?) Способ отлова и обработки ошибок, возникающих в XMLReader из-за некорректного файла - в частности, не экранированных символов.Предварительная подготовка с Tidy (и т. Д.) Не является супер привлекательным вариантом, кто-нибудь знает способ просто пропустить нарушающий узел и двигаться прямо?

Описательная версия:

Мы все знаем, что это не XML, если он не сформирован должным образом, но давайте будем честными - это происходит.Клиент регулярно загружает массивные (50-100 МБ +) XML-файлы, которые необходимо прочитать в mysql.XMLReader - очевидный выбор, и мы написали оболочку, которая хорошо работает для наших нужд.

Иногда возникает ошибка, и read () не в состоянии убить импорт - drat!Почти всегда это не экранированный символ (например, "&"), который все запутывает.В большинстве случаев мы просто заставляем клиента вызывать поставщика данных и требовать, чтобы он исправил свой дефектный файл.К сожалению, поставщики данных не всегда обязательны и / или своевременны.Было бы замечательно, если бы мы могли просто уловить ошибку и перейти прямо к следующему узлу.

Я потратил довольно много времени, пытаясь прочитать / взломать этот узел, и не могу найти ничего, что стоило бы просмотреть.Я что-то упускаю из виду?

Этот вопрос SO казался многообещающим, но он просто не дал никаких результатов.Передача 1 кажется, что он должен попросить Reader о восстановлении, но мы просто не видим никаких попыток / различных сообщений об ошибках и т. Д. Вот соответствующий код, описывающий подход:

$xml->open($file, null, LIBXML_NOERROR | LIBXML_NOWARNING | 1);

Я всегда могпредварительная обработка с Tidy, но должен быть лучший способ.

Я рассмотрел несколько более «творческих» подходов, таких как прослушивание следующего Read () с помощью метода try / catch после завершения логики для текущего узла,но это кажется неуклюжим в лучшем случае .Также кажется, что может быть эмуляция Read () с помощью специальной функции / оболочки, которая помогает перемещаться по узлам и включает обработку ошибок, но у меня такое чувство, что я упрощаю вещи.

Итак, подведем итоги: когда read () не удается, как я могу перехватить ошибку и двигаться дальше?Есть ли шанс, что мы увидим, какая ошибка появляется (по крайней мере, сообщение, которое выбросил бы XMLReader)?

$xml = new XMLReader();
$xml->open($file);

while ($xml->read()) {  

}

Ответы [ 3 ]

2 голосов
/ 28 ноября 2012

По поводу части вопроса "see the error":

http://php.net/manual/en/function.libxml-use-internal-errors.php Если этот параметр является ложным значением по умолчанию, предупреждение PHP будет срабатывать при любом недопустимом XML. Другими словами, вы должны были это увидеть: p Вы просто не обращали внимания или у вас есть действующий параметр или собственный обработчик ошибок, который скрывает от вас предупреждения PHP.

Если вы вызываете вышеуказанную функцию с true, предупреждение не будет сгенерировано, и вместо этого будут накапливаться ошибки во внутреннем массиве, возвращаемом этой функцией:

http://www.php.net/manual/en/function.libxml-get-errors.php

Насчет части "двигаться вперед", боюсь, что cweiske был прав, и это невозможно сделать. Вы можете предварительно проверить свой XML на наличие ошибок с помощью какого-либо инструмента (даже анализируя его с помощью XMLReader) и попытаться исправить найденные ошибки, например удалить / заменить недопустимые символы, но затем вам нужно будет перезапустить анализ исправленных данных.

2 голосов
/ 01 марта 2011

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

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

1 голос
/ 26 июня 2014

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

Этот фильтр HTML в XML делает это. Используйте это как

$dsn = "php://filter/read=htmltoxml.entities/resource=" . $url;
$xml = XMLReader::open($dsn);
...