То, что я знаю из XMLReader
даже имеет постоянную XMLReader::XML_DECLARATION
, я никогда не испытывал его при прохождении документа с XMLReader::read()
в XMLReader::$nodeType
собственности.
Похоже, что он пропускается, и я также задавался вопросом, почему это так, и я еще не нашел никакого флага или возможности изменить это поведение.
Для вывода XMLReader
всегда возвращает кодированные строки UTF-8. Это то же самое, что и в других частях на основе libxml в PHP. Так что с этой стороны все ясно. Но я предполагаю, что это не та часть, которая вам интересна, но конкретный ввод строки в файл, который вы открываете с помощью XMLReader::open()
.
Не определенно для XMLReader
Я однажды создал a utility class I named XMLRecoder
, который способен обнаруживать кодировку XML-строки на основе объявления XML, а также на основе спецификации. Я думаю, вы должны сделать то и другое. Это одна часть, я думаю, что вам все равно нужно использовать регулярные выражения, но поскольку объявление XML должно быть первым, а также является инструкцией по обработке (PI), которая является very well and strict defined, вы должны быть в состоянии заглянуть туда.
Это некоторые из них связаны часть из 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-документов, однако, не многие из них были со спецификациями. Как вы можете видеть, порядок обнаружения оптимизирован для более распространенных сценариев при одновременном рассмотрении дублирующих двоичных паттернов между различными спецификациями.Большинство документов, с которыми я столкнулся, не имеют спецификации, и вам в основном нужно выяснить, закодирован ли документ UTF-32.
Надеюсь, это по крайней мере дает некоторые идеи.
Да, документация довольно бедна. Я нахожу только самую общую информацию, _ «Важно отметить, что внутри libxml использует кодировку UTF-8 и, таким образом, кодировка полученного содержимого всегда будет в кодировке UTF-8». _ - но никак не для получения информации об исходном документе. Если никакое другое решение не появится, я, возможно, прочитаю первую строку документа отдельно и с помощью RegExp проанализирую эту информацию вручную, если это важно. – CBroe