在这个问题中,讨论了如何使用流解析PHP中的大型XML文档,以便不必将整个文档放入内存中。
但是,XMLReader
类似乎不适合分析 XML 文档中的大型文本节点。由于我使用的 API 将 base64 编码的文件作为 XML 文档的值以及一些元数据发送,因此我正在寻找一种流式传输这些文本节点的方法,而不是将值作为字符串返回:
<?php
$reader = XMLReader::open($someStream);
// $reader->read() until a node is reached
// The following puts the whole text node in memory, rather than creating a stream
$content = $reader->value;
?>
是否可以将$reader->value
变成溪流?
我想出的是使用PHP的低级XML解析器和一些流函数。
$input = fopen('input.xml', 'r');
$output = fopen('output.txt', 'w');
stream_filter_append($output, 'convert.base64-decode');
这些被传递给创建 XML 解析器的类:
public function __construct($input, $output) {
// ...
$this->xml = xml_parser_create();
xml_set_object($this->xml, $this);
xml_set_element_handler($this->xml, 'start', 'end');
xml_set_character_data_handler($this->xml, 'character');
}
start
和 end
方法用于在 XML 中查找正确的元素,character
方法将内容写入输出流:
protected function character($parser, $data)
{
if ($this->match()) {
fwrite($this->output, $data);
}
}
高效的部分是我们调用解析器的地方,它一次只读取可管理的块:
while ($data = fread($this->input, $bufferSize = 1024)) {
xml_parse($this->xml, $data, feof($this->input) or $this->done);
}
$this->done
可以在start
或end
处理程序中设置,就我而言,一旦找到匹配项,我就会完全删除处理程序。
由于这些旧的 php 函数不会抛出,因此当然仍然必须实现一些安全检查。