我上一个问题的某种后续:for loop - move deeper on numeric key in multidimensional array
我有这个数组作为输入:
Array
(
[0] => apl_struct Object
(
[funcname] => say
[args] => Array
(
[0] => Array
(
[0] => apl_struct Object
(
[funcname] => text
[args] => Array
(
[value] => hello
)
)
)
)
)
)
我现在有 2 个功能为我工作。 一个是仅用于获取关联数组中的下一个键/值的函数。 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;}
}
下一个函数是我的执行器或构造器。他为我创建了一个半 xmlstruct。 我尝试添加递归来跳过数字键。它们显然是废话,可以跳过。
然后我想检查非数字键的所有值是否都是数组。 如果它是一个数组,它指示要遵循的参数,输出应如下所示:INPUT。
如果不是,它要么是函数名 (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;
}
Here是一个 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"
}
}
}
}
}
然后,您在该数组中找到 'funcname'
($p = array_search($key, $keys)
) 并创建一个仅包含数组中的下一项:
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()
破坏,以删除您希望找到的 key 来构建它。
可以通过提前从内部递归返回来解决重复值。现在,您正在递归,处理“内部”节点,然后返回到顶部并再次处理它们。
相反,我们可以完全删除 getnext
(因为它甚至没有做你想要的事情),我们可以只使用 array_shift而不是丢弃数组最左边的值。然后我们继续像平常一样处理 $array
。
关于php foreach 多维数组递归不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26518573/