我正在编写解析器,并尝试使用异常进行良好的错误处理。
以下示例代码:
<?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_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中,无论如何都会抛出错误。
答案 0 :(得分:4)
看起来除了使用@
之外没有办法抑制警告,因为read()
的php源代码有以下几行:
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()
中的实际解析错误。
答案 1 :(得分:4)
从理解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在第一次出错后没有完全失败 - 它会继续并带来一系列有用的问题。在第一个问题之后,有时打印出所有发现的问题而不是中断处理可能是有用的。
我最关心的是XMLReader中存在isValid函数:) 我认为这实际上是一种解决方法,但它在处理匹配95%的XMLReader用例之前非常有效并且验证,因为它用于大型xml集合处理。