因为您的输入数据格式很好,您可以创建一个非常简单的递归后代解析器 - 甚至不涉及那么多递归。或者只是一个简单的堆栈:
$props = array_filter(array_map('trim', explode("\n", $prop)));
$stack = [$node = $xml = new SimpleXMLElement('<root/>')];
foreach ($props as $str)
{
if ($str === '}') {
array_pop($stack);
$node = end($stack);
continue;
}
if (preg_match('~^(\w+) {$~', $str, $matches)) {
$node = $stack[] = $node->addChild($matches[1]);
continue;
}
if (preg_match('~^(\w+):\s*(.*)$~', $str, $matches)) {
$node->addChild($matches[1], htmlspecialchars($matches[2]));
continue;
}
throw new UnexpectedValueException(sprintf('Unable to parse: "%s"', $str));
}
$xml->asXML('php://output');
您的第二个示例(以前缺少)的输出是(美化的):
<?xml version="1.0"?>
<root>
<button>
<large>
<bond>
<width>10px;</width>
<height>10px;</height>
</bond>
<style>
<background>
<color>#ffffff;</color>
<image>url(www.px.com/aui.png) -10px;</image>
<another>
<width>100px;</width>
<height>100px;</height>
</another>
</background>
</style>
</large>
<small>
<bond>
<width>10px;</width>
<height>10px;</height>
</bond>
<style>
<color>#fff;</color>
<border>1px solid #000;</border>
</style>
</small>
</button>
</root>
我建议您在这里使用 XML,因为它可以比不能有重复键的数组更好地表示结构。
也可以使用递归函数调用而不是堆栈。但这需要将输入流包装在不倒带迭代器中以不中断(或使用array_shift
但我不太喜欢):
$parse = function($p, SimpleXMLElement $t) use (&$parse) {
foreach($p as $s) {
if ($s === '}') {
break;
}
if (preg_match('~^([^ ]+) {$~', $s, $m)) {
$p->next();
$parse($p, $t->addChild($m[1]));
continue;
}
if (preg_match('~^([^:]+):\s*(.*)$~', $s, $m)) {
$n = $t->addChild($m[1], htmlspecialchars($m[2]));
continue;
}
}
};
$props = array_filter(array_map('trim', explode("\n", $prop)));
$xml = new SimpleXMLElement('<root/>');
$parse(new NoRewindIterator(new ArrayIterator($props)), $xml);
$xml->asXML('php://output');