我读过那篇著名的文章。我见过这些尝试,成功和失败都是有限的。哦,火焰之战,这里和其他地方。
但这是可以做到的。
虽然我知道实际的论点(read fact)是正则表达式不适合解析结构化数据树,因为它们无法监视和更改状态,但我觉得有些人盲目地放弃了这种可能性。应用程序逻辑是保持状态所必需的,但正如这个工作示例所示,它是可以做到的。
相关片段如下:

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>

对。是的。
虽然我很欢迎这个线程成为一个社区wiki,因为它满足了要求,但我将把这个声明变成一个问题。
专注于正则表达式,有谁能预见到这样一种情况:在这种情况下,当对格式良好的标记使用正则表达式时,它会失败得可怕?我想我已经把所有的底子都盖好了。
我无意“搅锅”,但我想从硬币的两面看一看。
还要注意,编写本文的目的是SimpleXML太简单,而DOM对我的一个应用程序来说太严格。

最佳答案

专注于正则表达式,有谁能预见到这样一种情况:在这种情况下,当对格式良好的标记使用正则表达式时,它会失败得可怕?当对XML一致性测试套件运行时,它拒绝多少格式良好的XML文档,接受多少格式错误的XML文档?
共享xml社区文化的人可能最大的反对意见是,它不仅会解析大多数格式良好的xml文档,还会解析大多数非xml文档,因为它不会告诉您它们的格式不正确。现在,也许您认为这在您的环境中没有太大关系—但最终,如果您接受格式不正确的文档,那么人们将开始向您发送格式不正确的文档,不久之后,您将陷入与HTML相同的混乱中,因为遗留原因,您必须接受任何旧的垃圾。
我不太了解php,无法快速判断代码对格式良好的xml的工作情况。但我质疑这样做的动机——当现成的好的、正确的、快速的和免费的XML解析器都可以使用时,为什么有一个地球会希望手工编写一个廉价、肮脏和缓慢的XML解析器呢?

09-12 04:44
查看更多