Анализ данных XML / XHTML с помощью Regex

Я прочитал знаменитый пост. Я видел попытки, как с ограниченным успехом, так и с неудачей. О, пламенные войны, как здесь, так и в другом месте.

Но это может быть сделано.

Хотя я знаю, что фактический аргумент (факт чтения) заключается в том, что регулярные выражения не подходят для синтаксического анализа структурированных деревьев данных из-за их неспособности контролировать и изменять состояние, я чувствую, что некоторые слепо отбрасывают возможность. Логика приложения необходима для сохранения состояния, но, как показывает этот рабочий пример, это можно сделать.

Ниже приведен соответствующий фрагмент:

const PARSE_MODE_NEXT = 0; const PARSE_MODE_ELEMENT = 1; const PARSE_MODE_ENTITY = 3; const PARSE_MODE_COMMENT = 4; const PARSE_MODE_CDATA = 5; const PARSE_MODE_PROC = 6; protected $_parseModes = array( self::PARSE_MODE_NEXT => '% < (?: (?: (?<entity>!) (?: (?<comment>--) | (?<cdata>\[CDATA\[) ) ) | (?<proc>\?) )? %six', self::PARSE_MODE_ELEMENT => '% (?<close>/)? (?<element> .*? ) (?<empty> / )? > (?<text> [^<]* ) %six', self::PARSE_MODE_ENTITY => '% (?<entity> .*? ) > (?<text> [^<]* ) %six', self::PARSE_MODE_COMMENT => '% (?<comment> .*? ) --> (?<text> [^<]* ) %six', self::PARSE_MODE_CDATA => '% (?<cdata> .*? ) \]\]> (?<text> [^<]* ) %six', self::PARSE_MODE_PROC => '% (?<proc> .*? ) \?> (?<text> [^<]* ) %six', ); public function load($string){ $parseMode = self::PARSE_MODE_NEXT; $parseOffset = 0; $context = $this; while(preg_match($this->_parseModes[$parseMode], $string, $match, PREG_OFFSET_CAPTURE, $parseOffset)){ if($parseMode == self::PARSE_MODE_NEXT){ switch(true){ case (!($match['entity'][0] || $match['comment'][0] || $match['cdata'][0] || $match['proc'][0])): $parseMode = self::PARSE_MODE_ELEMENT; break; case ($match['proc'][0]): $parseMode = self::PARSE_MODE_PROC; break; case ($match['cdata'][0]): $parseMode = self::PARSE_MODE_CDATA; break; case ($match['comment'][0]): $parseMode = self::PARSE_MODE_COMMENT; break; case ($match['entity'][0]): $parseMode = self::PARSE_MODE_ENTITY; break; } }else{ switch($parseMode){ case (self::PARSE_MODE_ELEMENT): switch(true){ case (!($match['close'][0] || $match['empty'][0])): $context = $context->addChild(new ZuqMLElement($match['element'][0])); break; case ($match['empty'][0]): $context->addChild(new ZuqMLElement($match['element'][0])); break; case ($match['close'][0]): $context = $context->_parent; break; } break; case (self::PARSE_MODE_ENTITY): $context->addChild(new ZuqMLEntity($match['entity'][0])); break; case (self::PARSE_MODE_COMMENT): $context->addChild(new ZuqMLComment($match['comment'][0])); break; case (self::PARSE_MODE_CDATA): $context->addChild(new ZuqMLCharacterData($match['cdata'][0])); break; case (self::PARSE_MODE_PROC): $context->addChild(new ZuqMLProcessingInstruction($match['proc'][0])); break; } $parseMode = self::PARSE_MODE_NEXT; } if(trim($match['text'][0])){ $context->addChild(new ZuqMLText($match['text'][0])); } $parseOffset = $match[0][1] + strlen($match[0][0]); } } 

Это полно? Неа.

Разве это невозможно? Конечно нет.

Это быстро? Не тестировали, но я не могу себе представить, что это так же быстро, как DOM .

Поддерживает ли он XPath / XQuery? Очевидно нет.

Проверяет ли он или выполняет какие-либо другие вспомогательные задачи? Конечно, нет.

Будет ли это заменять DOM? Конечно нет.

Однако , будет ли это разбирать это?

 <?xml version="1.0" encoding="utf-8"?> <!ENTITY name="value"> <root> <node> <node /> Foo <node name="value"> <node>Bar</node> </node> <!-- Comment --> </node> <node> <[CDATA[ Character Data ]]> </node> </root> 

Да. Да, это будет.

Хотя я бы приветствовал эту нить, становясь Community Wiki, учитывая, что она соответствует требованиям, я превращу это утверждение в вопрос.

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

Я не собираюсь «помешивать горшок», однако мне хотелось бы получить некоторое представление с обеих сторон монеты.

Заметим также, что цель написания этого заключалась в том, что SimpleXML был слишком простым, а DOM был слишком строгим для одного из моих приложений.

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

Возможно, самым большим возражением со стороны тех, кто разделяет культуру сообщества XML, является то, что он не только проанализирует наиболее хорошо сформированные XML-документы, но и проанализирует большинство документов, отличных от XML, в том смысле, что он не говорит вам, что они плохо сформирован. Теперь, возможно, вы думаете, что это не имеет большого значения в вашей среде, но, в конце концов, если вы примете неверно оформленные документы, люди начнут посылать вам плохо оформленные документы, и вскоре вы будете в том же беспорядке, что и HTML , где вы должны принять любой старый мусор по наследственным причинам.

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