我已经阅读了这篇著名的帖子,也见过尝试的结果(有成功也有失败)。在这里和其他地方都有激烈的口水战。
但是它是可以做到的。
虽然我知道实际的论点(读作事实)是正则表达式不适用于解析结构化数据树,因为它们不能监视和更改状态,但我觉得有些人盲目地丢弃了这种可能性。应用程序逻辑是必要的,以保持状态,但正如这个有效的示例所显示的那样,它是可以做到的。
相关片段如下:
但是它是可以做到的。
虽然我知道实际的论点(读作事实)是正则表达式不适用于解析结构化数据树,因为它们不能监视和更改状态,但我觉得有些人盲目地丢弃了这种可能性。应用程序逻辑是必要的,以保持状态,但正如这个有效的示例所显示的那样,它是可以做到的。
相关片段如下:
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
对于我的某些应用程序来说太严格了。
SimpleXML
太简单了,对我所需的内容支持有限;DOM
太严格了,导致解决问题比它带来更多问题;我需要一些迁移友好型的东西,可以轻松地包含在任何项目中,而不受环境限制;对于它的目的,我不关心验证,只关心解析和重构结构化文档的能力。然而,速度是一个问题,超过DOM
30倍以上(100,000次测试迭代),它失败了,无法使用。:( - Dan Lugg