php foreach多维数组递归无法正常工作?

时间:2014-10-22 22:59:55

标签: php recursion multidimensional-array foreach associative-array

对我上一个问题的某种跟进: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
                    )
                )
            )
        )
    )
)

我现在有两个功能为我工作。 一个是仅用于获取关联数组中的下一个键/值的函数。 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),也可能是我们的实际值,例如&#34;你好&#34;。

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>

提前致谢

2 个答案:

答案 0 :(得分:1)

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()损坏,以删除您希望找到的密钥以构建它。

可以通过先前从内部递归返回来解决重复值。现在,您正在递归,处理“内部”节点,然后返回到顶部并再次处理它们。

相反,我们可以完全删除getnext(因为它甚至不能做你想要的),我们可以使用array_shift代替丢弃数组的最左边的值。然后我们继续正常处理$array

答案 1 :(得分:0)

经过一段时间后,我想出了解决问题的解决方案:

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的