我所知道的XMLReader
即使它有 常数,我在 属性中XMLReader::XML_DECLARATION
遍历文档时也从未体验过它。XMLReader::read()
XMLReader::$nodeType
看起来它被跳过了,我也想知道为什么会这样,我还没有找到任何标志或选项来改变这种行为。
对于输出,XMLReader
始终返回 UTF-8 编码的字符串。这与 PHP 中其他基于 libxml 的部分相同。所以从那一边,一切都清楚了。但我认为这不是您感兴趣的部分,而是您使用打开的文件中的具体字符串输入XMLReader::open()
。
不是专门因为XMLReader
我曾经创建了一个我命名的实用程序类XMLRecoder
,它能够基于 XML 声明和 BOM 检测 XML 字符串的编码。我认为你应该两者都做。这是我认为你仍然需要使用正则表达式的一部分,但由于 XML 声明必须是第一件事,而且它是一个处理指令 (PI),它的定义非常好和严格,你应该能够在那里窥视。
这是XMLRecoder
代码中的一些相关部分:
### excerpt from https://gist.github.com/hakre/5194634
/**
* pcre pattern to access EncodingDecl, see <http://www.w3.org/TR/REC-xml/#sec-prolog-dtd>
*/
const DECL_PATTERN = '(^<\?xml\s+version\s*=\s*(["\'])(1\.\d+)\1\s+encoding\s*=\s*(["\'])(((?!\3).)*)\3)';
const DECL_ENC_GROUP = 4;
const ENC_PATTERN = '(^[A-Za-z][A-Za-z0-9._-]*$)';
...
($result = preg_match(self::DECL_PATTERN, $buffer, $matches, PREG_OFFSET_CAPTURE))
&& $result = $matches[self::DECL_ENC_GROUP];
正如这表明它一直到编码,所以它不完整。但是,对于提取编码的需要(以及您需要的版本),它应该可以完成这项工作。我已经针对大量(数千)随机 XML 文档进行了测试以进行测试。
另一部分是BOM检测:
### excerpt from https://gist.github.com/hakre/5194634
const BOM_UTF_8 = "\xEF\xBB\xBF";
const BOM_UTF_32LE = "\xFF\xFE\x00\x00";
const BOM_UTF_16LE = "\xFF\xFE";
const BOM_UTF_32BE = "\x00\x00\xFE\xFF";
const BOM_UTF_16BE = "\xFE\xFF";
...
/**
* @param string $string string (recommended length 4 characters/octets)
* @param string $default (optional) if none detected what to return
* @return string Encoding, if it can not be detected defaults $default (NULL)
* @throws InvalidArgumentException
*/
public function detectEncodingViaBom($string, $default = NULL)
{
$len = strlen($string);
if ($len > 4) {
$string = substr($string, 0, 4);
} elseif ($len < 4) {
throw new InvalidArgumentException(sprintf("Need at least four characters, %d given.", $len));
}
switch (true) {
case $string === self::BOM_UTF_16BE . $string[2] . $string[3]:
return "UTF-16BE";
case $string === self::BOM_UTF_8 . $string[3]:
return "UTF-8";
case $string === self::BOM_UTF_32LE:
return "UTF-32LE";
case $string === self::BOM_UTF_16LE . $string[2] . $string[3]:
return "UTF-16LE";
case $string === self::BOM_UTF_32BE:
return "UTF-32BE";
}
return $default;
}
通过 BOM 检测,我也确实针对同一组 XML 文档运行了此操作,但是,使用 BOM 的并不多。如您所见,检测顺序针对更常见的场景进行了优化,同时处理了不同 BOM 之间的重复二进制模式。我遇到的大多数文档都没有 BOM,您主要需要它来确定文档是否是 UTF-32 编码的。
希望这至少能提供一些见解。