我最后一个问题的后续内容:对于循环,在多维数组中的数字键上移动更深
我有这个数组作为输入:
Array
(
[0] => apl_struct Object
(
[funcname] => say
[args] => Array
(
[0] => Array
(
[0] => apl_struct Object
(
[funcname] => text
[args] => Array
(
[value] => hello
)
)
)
)
)
)
我现在有两个功能在为我工作。一个是仅用于获取关联数组中的下一个键/值的函数。next()、prev()等都不像索引数组那样对我有效:
function getnext($array, $key) {
$keys = array_keys($array);
if ((false !== ($p = array_search($key, $keys))) && ($p < count($keys) - 1)) {
return array('key' => $keys[++$p], 'value' => $array[$keys[$p]]);
} else {return false;}
}
下一个函数是我的执行器或构造器。他为我创建了一个半xml结构。我试图为跳过数字键添加递归。它们显然是无稽之谈,可以跳过。
然后我想检查非数字键的所有值是否都是数组。如果它是一个数组,它指示要遵循的参数和输出应该看起来像:INPUT。
如果不是,它要么是functionname(funcname),要么实际上是一个真正的值,比如"hello"。
function arr2xml($array, $level = 1, $pos = 1) {
$xml = '';
foreach ($array as $key => $value) {
if (is_object($value)) {$value = get_object_vars($value);}// convert object to array
if (is_numeric($key)) {
$xml .= arr2xml($value);
} else {
if (!is_array($value)) {
switch ($key) {
case 'funcname':
$nextkey = getnext($array, $key);
$xml .= str_repeat("'t", $level) . "<apl:$value>'n";
$xml .= arr2xml($nextkey['value'], $level++);
$xml .= str_repeat("'t", $level) . "</apl:$value>'n";
break;
case 'value':
$xml .= str_repeat("'t", $level) . "'t$value'n";
break;
}
} else {
$xml .= str_repeat("'t", $level) . "<$key pos='$pos'>'n't";
$xml .= arr2xml($value, $level++, $pos++);
$xml .= str_repeat("'t", $level) . "</$key>'n";
}
}
}
return $xml;
}
但到目前为止,我从中得到的是:函数名称插入正确。它是说和文本。此外,在某些异常情况下,-tag和值会正确执行。
<apl:say>
<apl:text>
hello
</apl:text>
<args pos='1'>
hello
</args>
</apl:say>
<args pos='1'>
<apl:text>
hello
</apl:text>
<args pos='1'>
hello
</args>
</args>
</xml>
对我来说,递归似乎并没有真正起作用。我是不是遗漏了什么?我试着从前面提到的帖子中重建它。
此外,我想知道我在这里得到的多重输出。标签似乎填对了,但实际的安排让我很困惑。
我原以为输出是这样的:
<apl:say>
<args pos='1'>
<apl:text>
<args pos='1'>
hello
</args>
</apl:text>
</args>
</apl:say>
提前感谢
TL;DR
它是(完全多余的函数)getnext()
和arr2xml()
如何递归的组合。我在这里提供了一个arr2xml()
替换功能,它可以随心所欲,而不需要getnext()
。
下面将详细描述代码中出现的错误,以及我建议如何修复它。
function arr2xml($array, $level = 0, $pos = 1) {
$xml = '';
foreach ($array as $key => $value) {
if (is_object($value)) {
$value = get_object_vars($value);
}
if (is_numeric($key)) {
$xml .= arr2xml($value, $level+1);
continue;
} else {
if (!is_array($value)) {
switch ($key) {
case 'funcname':
array_shift($array);
$xml .= str_repeat(" ", $level) . "<apl:$value>'n";
$xml .= arr2xml($array, $level+1);
$xml .= str_repeat(" ", $level) . "</apl:$value>'n";
return $xml;
case 'value':
$xml .= str_repeat(" ", $level) . " $value'n";
return $xml;
}
} else {
$xml .= str_repeat(" ", $level) . "<$key pos='$pos'>'n ";
$xml .= arr2xml($value, $level+1, $pos+1);
$xml .= str_repeat(" ", $level) . "</$key>'n";
return $xml;
}
}
}
return $xml;
}
这里有一个eval.in,显示了这个新函数在你提供的相同数据结构上的使用,或多或少地给了你想要的输出(空白可能不是你想要的,我把它留给你练习。)
你的代码出了什么问题
当funcname
为'say'
时,条件case 'funcname':
调用getnext()
,$key
设置为'funcname'
,$array
设置为:
array(2) {
["funcname"]=>
string(3) "say"
["args"]=>
array(1) {
[0]=>
array(1) {
[0]=>
object(apl_struct)#1 (2) {
["funcname"]=>
string(4) "text"
["args"]=>
array(1) {
["value"]=>
string(5) "hello"
}
}
}
}
}
然后在该数组($p = array_search($key, $keys)
)中找到'funcname'
,并创建一个仅包含数组中下一项的值的新数组:
return array('key' => $keys[++$p], 'value' => $array[$keys[$p]]);
结果是一个不再包含'args'
密钥的数组:
array(2) {
["key"]=>
string(4) "args"
["value"]=>
array(1) {
[0]=>
array(1) {
[0]=>
object(apl_struct)#1 (2) {
["funcname"]=>
string(4) "text"
["args"]=>
array(1) {
["value"]=>
string(5) "hello"
}
}
}
}
}
因此,你永远不会得到你想要的标签,因为getnext()
已经破坏了数据结构,删除了你想要找到的密钥来构建它
重复的值可以通过早些时候从内部递归返回来解决。现在,您正在递归,处理"内部"节点,然后返回顶部并再次处理它们。
相反,我们可以完全删除getnext
(因为它甚至不做你想要的事情),我们可以只使用array_shift来丢弃数组的最左边的值。然后,我们像往常一样继续处理$array
。
花了一段时间后,我为我的问题想出了这个解决方案:
function apl2xml($array, $tlevel = 0) {
$ret = '';
$ret .= str_repeat("'t", $tlevel) . "<apl>'n";
foreach ($array as $key => $value) {
$ret .= $this->aplstruct2xml($value, $tlevel + 1);
}
$ret .= str_repeat("'t", $tlevel) . "</apl>'n";
return $ret;
}
function aplstruct2xml($apl_struct, $tlevel = 0) {
$ret = '';
if ($apl_struct->funcname == 'text') {
$ret .= str_repeat("'t", $tlevel) . "<text>'n";
$ret .= str_repeat("'t", $tlevel);
$ret .= $apl_struct->args[0] . "'n";
$ret .= str_repeat("'t", $tlevel) . "</text>'n";
} else {
$ret .= str_repeat("'t", $tlevel) . "<aplfunc:{$apl_struct->funcname}>'n";
foreach ($apl_struct->args as $key => $value) {
$ret .= str_repeat("'t", $tlevel + 1) . "<arg pos='$key'>'n";
$ret .= $this->apl2xml($value, $tlevel + 2);
$ret .= str_repeat("'t", $tlevel + 1) . "</arg>'n";
}
$ret .= str_repeat("'t", $tlevel) . "</aplfunc:{$apl_struct->funcname}>'n";
}
return $ret;
}
事实证明,我根本不需要任何递归。。
所谓的apl只是由一个apl_struct组成,它可以包含更多的apl/apl_struct's