Я нахожусь в написании парсера и стараюсь делать хорошую обработку ошибок с исключениями.
Следующий пример кода:
<?php $xml = <<<XML <?xml version="1.0"?> <rootElem> XML; $reader = new XMLReader(); $reader->xml($xml, null, LIBXML_NOERROR | LIBXML_NOWARNING); $reader->read();
Выдает:
PHP Warning: XMLReader::read(): An Error Occured while reading in /Users/evert/code/xml/errortest.php on line 11 PHP Stack trace: PHP 1. {main}() /Users/evert/code/xml/errortest.php:0 PHP 2. XMLReader->read() /Users/evert/code/xml/errortest.php:11
Добавление:
libxml_use_internal_errors(true);
Не имеет никакого эффекта.
Моя цель – проверить ошибки позже (с помощью libxml_get_errors()
) и выбросить исключение. Я считаю, что единственным решением является использование оператора молчания ( @
), но это похоже на плохую идею.
Обратите внимание, что когда я не LIBXML
константы LIBXML
и не использую libxml_use_internal_errors
, я получаю другую ошибку, например:
PHP Warning: XMLReader::read(): /Users/evert/code/xml/:2: parser error : Extra content at the end of the document in /Users/evert/code/xml/errortest.php on line 11
Это говорит о том, что основная библиотека libxml действительно подавляет ошибку, но в XMLReader все равно возникает ошибка.
Похоже, нет способа подавить предупреждение, кроме использования @
, поскольку источник php для read()
имеет следующие строки:
retval = xmlTextReaderRead(intern->ptr); if (retval == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "An Error Occured while reading"); RETURN_FALSE; } else { RETURN_BOOL(retval); }
Таким образом, только фактические ошибки синтаксического анализа внутри xmlTextReaderRead()
подавляются libxml_use_internal_errors(true);
или параметры, переданные в XMLReader::xml()
.
Из моего понимания XMLReader, чтобы проверить документ, необходимо выполнить один полный проход по всему документу.
Что я делаю:
// Enable internal libxml errors libxml_use_internal_errors(true); $xml = new \XMLReader(); $xsd='myfile.xsd'; $xml->open('myfile.xml'); $xml->setSchema ($xsd); // Conduct full pass through document. The only reason is to force validation. while (@$xml->read()) { }; // empty loop if (count(libxml_get_errors ())==0) { echo "provided xml is well formed and xsd-valid"; // Now you can start processing without @ as document was validated against xsd and is xml-wellformed } else echo "provided xml is wrong and/or not xsd-valid. stopping";
Конечно, вы можете проверить ошибки внутри пустого цикла, а затем сразу же после первой ошибки сломаться. Я заметил, что XMLReader не полностью сбой после первой ошибки – он продолжается и приносит множество проблем, которые полезны. Иногда может быть полезно распечатать все обнаруженные проблемы вместо обработки прерывания после первой проблемы.
Моя самая большая проблема заключается в том, что функция isValid существует в XMLReader 🙂 Я думаю, что это на самом деле своего рода обходной путь, но он работает очень хорошо и проверяет до того, как обработка соответствует 95% случаев использования XMLReader, поскольку она используется для обработки больших XML-коллекций.