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

Some kind of followup to my last question: for loop - move deeper on numeric key in multidimensional array

I have this array as input:

Array
(
  [0] => apl_struct Object
    (
      [funcname] => say
      [args] => Array
        (
          [0] => Array
            (
              [0] => apl_struct Object
                (
                  [funcname] => text
                  [args] => Array
                    (
                      [value] => hello
                    )
                )
            )
        )
    )
)

I now have 2 functions working for me. One is a func only for getting the next key/value in an associative array. None of the next(), prev(), etc. were working for me like on indexed arrays:

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;}
}

The next function is my executer or constructer. he creates a semi-xmlstruct for me. I tried to add recursion for skipping the numeric key. They're obviously nonsense and can be skipped.

I then want to check if all the values of the non-numeric keys are arrays or not. If it is an array it indicates arguments to be followed and output should look like: INPUT.

If not, it's either the functionname (funcname) or indeed a real value for us like "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>
";
              $xml .= arr2xml($nextkey['value'], $level++);
              $xml .= str_repeat("\t", $level) . "</apl:$value>
";
              break;
            case 'value':
              $xml .= str_repeat("\t", $level) . "\t$value
";
              break;
          }
        } else {
            $xml .= str_repeat("\t", $level) . "<$key pos='$pos'>
\t";
            $xml .= arr2xml($value, $level++, $pos++);
            $xml .= str_repeat("\t", $level) . "</$key>
";
        }
      }
  }

return $xml;
}

but what I am getting out of this so far is this: the function name was inserted right. it is say and text. also, in some wild circumstances, the -tag and the value are executed properly.

<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>

for me it looks like the recursion isn't really working. Am i missing something here? I've tried to rebuild it from previous mentioned post.

Also I'm wondering about the multiple output I am getting here. The tags seem to get filled right, but the actual arrangement is quite confusing for me.

I was expecting the output to look like this:

<apl:say>
  <args pos='1'>
    <apl:text>
      <args pos='1'>
      hello
      </args>
    </apl:text>
  </args>
</apl:say>

Thanks in advance

dsfgds4215
dsfgds4215 您输入的结构不一致-这是故意的吗?例如,你的一个'args'有一个数组,其中包含一个数组,该数组最后包含一个实际对象作为其第一个元素。其他args只是一个数组,字符串作为第一个元素。
接近 6 年之前 回复
douchongzhang9267
douchongzhang9267 请查看您的粘贴代码。应该是xml='';是$xml='';?并且$xml。=>arr2xml($value);应该是$xml。=arr2xml($value);?
接近 6 年之前 回复

2个回答

after some time spent i came up with this solution for my problem:

function apl2xml($array, $tlevel = 0) {
    $ret = '';
    $ret .= str_repeat("\t", $tlevel) . "<apl>
";

    foreach ($array as $key => $value) {
        $ret .= $this->aplstruct2xml($value, $tlevel + 1);
    }

    $ret .= str_repeat("\t", $tlevel) . "</apl>
";
    return $ret;
}

function aplstruct2xml($apl_struct, $tlevel = 0) {
    $ret = '';

    if ($apl_struct->funcname == 'text') {
        $ret .= str_repeat("\t", $tlevel) . "<text>
";

        $ret .= str_repeat("\t", $tlevel);
        $ret .= $apl_struct->args[0] . "
";

        $ret .= str_repeat("\t", $tlevel) . "</text>
";
    } else {
        $ret .= str_repeat("\t", $tlevel) . "<aplfunc:{$apl_struct->funcname}>
";

        foreach ($apl_struct->args as $key => $value) {
            $ret .= str_repeat("\t", $tlevel + 1) . "<arg pos='$key'>
";
            $ret .= $this->apl2xml($value, $tlevel + 2);
            $ret .= str_repeat("\t", $tlevel + 1) . "</arg>
";
        }

        $ret .= str_repeat("\t", $tlevel) . "</aplfunc:{$apl_struct->funcname}>
";
    }
    return $ret;
}

turns out that i did not need any recursion at all..

the so called apl just consisted of an apl_struct which could contain more apl's/apl_struct's

TL;DR

It's a combination of the (completely superfluous function) getnext(), and how your arr2xml() recurses. I've provided here an arr2xml() replacement function which will do what you want, without any need for getnext().

A detailed description of what went wrong in your code, and how I suggest fixing it, follows.

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>
";
            $xml .= arr2xml($array, $level+1);
            $xml .= str_repeat("    ", $level) . "</apl:$value>
";
            return $xml;
          case 'value':
            $xml .= str_repeat("    ", $level) . "    $value
";
            return $xml;
        }
      } else {
          $xml .= str_repeat("    ", $level) . "<$key pos='$pos'>
    ";
          $xml .= arr2xml($value, $level+1, $pos+1);
          $xml .= str_repeat("    ", $level) . "</$key>
";
          return $xml;
      }
    }
  }

  return $xml;
}

Here is an eval.in showing this new function in use on the same data structure you provided, giving you more or less the desired output (the whitespace may not be exactly what you wanted, I'll leave that as an exercise for you.)

What went wrong with your code

When funcname is 'say', the condition case 'funcname': calls getnext() with $key set to 'funcname' and $array set to:

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"
        }
      }
    }
  }
}

You then find 'funcname' in that array ($p = array_search($key, $keys)) and create a new array containing only the value of the next item in the array:

return array('key' => $keys[++$p], 'value' => $array[$keys[$p]]);

The result is an array that no longer contains the 'args' key:

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"
        }
      }
    }
  }
}

Thus, you will never get the tag you were hoping for, because the data structure has been corrupted by getnext() to remove the key you expected to find in order to construct it.

The duplicate values can be resolved by returning from the inner recursion earlier. Right now, you are recursing, processing the "inner" nodes, then returning back to the top and processing them again.

Instead, we can drop getnext entirely (since it doesn't even do what you wanted), and we can just use array_shift instead to throw away the left-most value of the array. We then continue processing $array like normal.

doudiao2335
doudiao2335 谢谢。 这样可行。 我完全错过了通过调用getnext()来创建新的,损坏的值的观点。 array_shift()现在就可以了。 我记得尝试过一次array_shift(),输出完全被破坏了。 似乎这个功能在另一个时刻是假的。
接近 6 年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问