Анализ данных XML / XHTML с помощью Regex - PullRequest
3 голосов
/ 25 января 2011

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

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

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

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

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>

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

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

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

У меня нет намерения "размешивать горшок", однако я хотел бы получить некоторое представление с обеих сторон медали.

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

1 Ответ

1 голос
/ 25 января 2011

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...