2013-03-18 3 views
3

Я в настоящее время переписываю класс PHP, который пытался разбить XML-файл на более мелкие куски, чтобы использовать XMLReader и XMLWriter вместо текущей базовой файловой системы и регулярного подхода.PHP XMLReader, получить версию и кодировку

Однако я не могу понять, как получить версию, кодировку и автономные флаги из преамбулы XML.

Начало моего файла тестового XML выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE fakedoctype SYSTEM "fake_doc_type.dtd"> 

<!-- 
This is a comment, it's here to try and get the parser to break in some way 
--> 

<root attribute="value" otherattribute="othervalue"> 

я могу открыть это хорошо с читателем и перемещаться по документу с чтением(), следующий() и т.д., но я просто не могу» t, похоже, все в <?xml ... ?>. Первое, что я могу получить, - это поддельный DOCTYPE.

Мой код тестирования выглядит следующим образом:

$a = new XMLReader(); 
var_dump ($a -> open ('/path/to/test/file.xml')) // true 
var_dump ($a -> nodeType); // 0 
var_dump ($a -> name); // "" 
var_dump ($a -> readOuterXML()); // '' 
var_dump ($a -> read()); // true 
var_dump ($a -> nodeType); // 10 
var_dump ($a -> readOuterXML()); // <!DOCTYPE fakedoctype SYSTEM "fake_doc_type.dtd"> 

Конечно, я мог бы просто всегда считать, XML 1.0, кодирования UTF8 и автономно = да, но ради справедливости я действительно предпочитаю быть в состоянии захватить каковы значения в исходном канале и использовать их при создании разделенных файлов.

Документация по XMLReader и XMLwriter кажется очень плохой, поэтому есть все шансы, что я просто что-то пропустил в документах. Кто-нибудь знает, что делать в этом случае?

+2

Да, документация довольно бедна. Я нахожу только самую общую информацию, _ «Важно отметить, что внутри libxml использует кодировку UTF-8 и, таким образом, кодировка полученного содержимого всегда будет в кодировке UTF-8». _ - но никак не для получения информации об исходном документе. Если никакое другое решение не появится, я, возможно, прочитаю первую строку документа отдельно и с помощью RegExp проанализирую эту информацию вручную, если это важно. – CBroe

ответ

3

То, что я знаю из 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.

Надеюсь, это по крайней мере дает некоторые идеи.

+0

Учитывая, что работа связана с выигрышем, я думаю, что, вероятно, лучше всего предположить UTF8. Я обязательно вернусь к этому ответу, если это окажется недостаточно адекватным. Честно говоря, у меня теперь больше проблем с XMLreader и XMLwriter, чем сейчас. :) Работать с ними не нравится. – GordonM

+0

Хорошо, если вы работаете с 'XMLReader', я могу предложить вам один проект, который у меня запущен, он называется [* XMLReaderIterator *] (http://git.io/xmlreaderiterator), который предлагает приятные интерфейсы вокруг XMLReader и решения проблем с универсальным программированием (итераторы): ['XMLReaderIterator' Github repro] (https://github.com/hakre/XMLReaderIterator), а также существует один файл (' XMLReaderIterator' gist release] (https: // gist. github.com/hakre/5147685) - может быть, это полезно. Также, если вы можете превратить свои проблемы в более общие вопросы здесь, на SO будет здорово, нам нужно больше XMLReader на основе QA :). – hakre

+0

Я бы сказал, что мы действительно можем сделать, это правильная документация для XMLReader и XMLWriter на php.net. :) Это далеко не стандарт всех остальных документов. – GordonM

Смежные вопросы