2

我使用 PHPzip://流包装器逐行解析大型 XML 文件。例如:

$stream_uri = 'zip://' . __DIR__ . '/archive.zip#foo.xml';
$reader     = new XMLReader();
$reader->open( $stream_uri, null );
$reader->read();

while ( true ) {
    echo( $reader->readInnerXml() . PHP_EOL );
    if ( ! $reader->next() ) {
        break;
    }
}

XML 文件通常会包含XMLReader不喜欢的狡猾的 UTF 控制字符。所以我想实现一个自定义流包装器,我可以将zip://流的输出传递给它,它将preg_replace在每一行运行一个来删除这些字符。

我的梦想是能够做到这一点:

stream_wrapper_register( 'xmlchars', 'XML_Chars' );
$stream_uri = 'xmlchars://zip://' . __DIR__ . '/archive.zip#foo.xml';

XMLReader愉快地阅读了整理好的节点。我已经找到了一种基于传递给我的包装器的路径来重建 zip 流 URI 的方法:

class XML_Chars {

    protected $stream_uri = '';
    protected $handle;

    function stream_open( $path, $mode, $options, &$opened_path ) {
        $parsed_url     = parse_url( $path );
        $this->stream_uri = 'zip:' . $parsed_url['path'] . '#' . $parsed_url['fragment'];

        return true;
    }

}

但是我对打开zip://流的最佳方式感到困惑,这样我就可以修改它的输出并将结果传递给XMLReader. 谁能给我有关如何实现它的任何指示?

4

1 回答 1

1

万一对其他人有用,我找到了解决问题的另一种方法:流过滤器。你这样定义它:

class UTF_Character_Filter extends php_user_filter {
    public function filter( $in, $out, &$consumed, $closing ) {
        while ( $bucket = stream_bucket_make_writeable( $in ) ) {
            $consumed += $bucket->datalen;
            // Remove characters in the hex range 0 - 8, B and C, E to 1F
            // i.e. all control characters except newline, tab and return
            $bucket->data = preg_replace( '|[\x0-\x8\xB-\xC\xE-\x1F]|ms', '', $bucket->data );
            stream_bucket_append( $out, $bucket );
        }

        return PSFS_PASS_ON;
    }
}

stream_filter_register( 'utf_character_filter', 'UTF_Character_Filter' );

并像这样使用它:

php://filter/read=utf_character_filter/resource=zip://archive.zip#import.xml

我仍然很想知道是否有人想出如何制作一个可以接受另一个流包装器输入的流包装器,因为它可能是一个方便的工具。

于 2018-10-31T14:41:59.523 回答