让 PHP 的 XMLReader 不会在无效文档中抛出 php 错误

Posted

技术标签:

【中文标题】让 PHP 的 XMLReader 不会在无效文档中抛出 php 错误【英文标题】:Getting PHP's XMLReader to not throw php errors in invalid documents 【发布时间】:2013-02-02 08:49:49 【问题描述】:

我正在编写解析器,并尝试对异常进行良好的错误处理。

以下示例代码:

<?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 中还是会抛出错误。

【问题讨论】:

也许实现trycatch 来跟踪错误? 它们不是例外,它们是传统的 PHP 错误。我可以使用 try..catch 的唯一方法是使用 set_error_handler,我想在编写库时避免这种情况,并且我不想更改全局状态。 【参考方案1】:

看起来除了使用@ 之外没有其他方法可以抑制警告,因为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);

因此,libxml_use_internal_errors(true); 或传递给 XMLReader::xml() 的选项只会抑制 xmlTextReaderRead() 中的实际解析错误。

【讨论】:

非常不幸;我找到了相同的线路并为其开了一张票:bugs.php.net/bug.php?id=64230 即使 @ 似乎对我不起作用 - 我尝试了 while (@$x->read()) ... ,但仍然收到错误消息。【参考方案2】:

根据我对 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 集合处理。

【讨论】:

以上是关于让 PHP 的 XMLReader 不会在无效文档中抛出 php 错误的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中使用 XmlReader 读取 Xml

XmlReader - 自关闭元素不会触发 EndElement 事件?

使用 PHP 和 XMLReader 解析 XML

PHP XMLReader 获取父节点?

PHP XMLReader 获取所有节点名称

php xml 文件读取 XMLReader