SimpleXML & PHP: Extract part of XML document & convert as Array

落爺英雄遲暮 提交于 2019-12-06 21:47:28

this might help

$obj = new SimpleXMLElement($xml);
$rtn = array();
$cnt = 0;
foreach($obj->xpath('///OSes/*/*') as $rec)
{
  foreach ($rec as $rec_obj)
  {
    if (!isset($rtn[$cnt]))
    {
      $rtn[$cnt] = array();
    }

    foreach ($rec_obj as $name=>$val)
    {
      $rtn[$cnt][(string)$name] = (string)$val;
    }
    ++$cnt;
  }
}

By modifying the xpath as others suggested as well, I came to this conclusion. It works with one helper function to re-format each xpath result node and uses array_reduce to iterate over the result. It then returns the converted result (Demo):

$xml = new SimpleXMLElement($xmlstr);
$elements = array_reduce(
    $xml->xpath('//OSes/*/*'),
    function($v, $w) {
        $w = array_values((array) $w); // convert result to array
        foreach($w as &$d) $d = (array) $d; // convert inner elements to array
        return array_merge($v, $w); // merge with existing
    }, 
    array() // empty elements at start
);

Output:

Array
(
    [0] => Array
        (
            [id] => centos5-32
            [name] => CentOS 5 - 32 bit
            [version] => 5
            [architecture] => 32
            [os] => centos
        )

    [1] => Array
        (
            [id] => centos5-64
            [name] => CentOS 5 - 64 bit
            [version] => 5
            [architecture] => 64
            [os] => centos
        )

    [2] => Array
        (
            [id] => centos6-32
            [name] => CentOS 6 - 32 bit
            [version] => 6
            [architecture] => 32
            [os] => centos
        )

    [3] => Array
        (
            [id] => centos6-64
            [name] => CentOS 6 - 64 bit
            [version] => 6
            [architecture] => 64
            [os] => centos
        )

    [4] => Array
        (
            [id] => ubuntu10-32
            [name] => Ubuntu 10 - 32 bit
            [version] => 10
            [architecture] => 32
            [os] => ubuntu
        )

    [5] => Array
        (
            [id] => ubuntu10-64
            [name] => Ubuntu 10 - 64 bit
            [version] => 10
            [architecture] => 64
            [os] => ubuntu
        )

)

I also opted for converting the original xpath result into an array of two levels, each time within the current level a key already exists, move the current entry to a new entry (Demo):

try
{
    $xml = new SimpleXMLElement($xmlstr);
    $elements = array();
    $curr = NULL;
    foreach($xml->xpath('//id | //name | //version | //architecture | //os') as $record)
    {
        $key = $record->getName();
        $value = (string) $record;
        if (!$curr || array_key_exists($key, $curr)) {
            unset($curr);
            $curr = array();
            $elements[] = &$curr;
        }
        $curr[$key] = $value;
    }
    unset($curr);
}
catch(Exception $e)
{
    echo $e->getMessage();
}

Result is like this then:

Array
(
    [0] => Array
        (
            [id] => centos5-32
            [name] => CentOS 5 - 32 bit
            [version] => 5
            [architecture] => 32
            [os] => centos
        )

    [1] => Array
        (
            [id] => centos5-64
            [name] => CentOS 5 - 64 bit
            [version] => 5
            [architecture] => 64
            [os] => centos
        )

    [2] => Array
        (
            [id] => centos6-32
            [name] => CentOS 6 - 32 bit
            [version] => 6
            [architecture] => 32
            [os] => centos
        )

    [3] => Array
        (
            [id] => centos6-64
            [name] => CentOS 6 - 64 bit
            [version] => 6
            [architecture] => 64
            [os] => centos
        )

    [4] => Array
        (
            [id] => ubuntu10-32
            [name] => Ubuntu 10 - 32 bit
            [version] => 10
            [architecture] => 32
            [os] => ubuntu
        )

    [5] => Array
        (
            [id] => ubuntu10-64
            [name] => Ubuntu 10 - 64 bit
            [version] => 10
            [architecture] => 64
            [os] => ubuntu
        )

)

Try this:

// flatten:
function arrayval1($any) {
  return array_values((array)$any);
}
function arrayval2($any) {
  return (array)$any;
}

// xml objects with xml objects:
$oses = $xml->xpath('//OSes/*/*');
// an array of xml objects:
$oses = array_map('arrayval1', $oses);
// merge to a flat array:
$oses = call_user_func_array('array_merge', $oses);
// xml objects -> arrays
$oses = array_map('arrayval2', $oses);
print_r($oses);

My result:

Array
(
    [0] => Array
        (
            [id] => centos5-32
            [name] => CentOS 5 - 32 bit
            [version] => 5
            [architecture] => 32
            [os] => centos
        )

    [1] => Array
        (
            [id] => centos5-64
            [name] => CentOS 5 - 64 bit
            [version] => 5
            [architecture] => 64
            [os] => centos
        )

    [2] => Array
        (
            [id] => centos6-32
            [name] => CentOS 6 - 32 bit
            [version] => 6
            [architecture] => 32
            [os] => centos
        )

    [3] => Array
        (
            [id] => centos6-64
            [name] => CentOS 6 - 64 bit
            [version] => 6
            [architecture] => 64
            [os] => centos
        )

    [4] => Array
        (
            [id] => ubuntu10-32
            [name] => Ubuntu 10 - 32 bit
            [version] => 10
            [architecture] => 32
            [os] => ubuntu
        )

    [5] => Array
        (
            [id] => ubuntu10-64
            [name] => Ubuntu 10 - 64 bit
            [version] => 10
            [architecture] => 64
            [os] => ubuntu
        )

)

If you're using PHP >= 5.3 (ofcourse you are, why whouldn't you) you can omit the nasty tmp function definitions and use cool anonymous functions for the mapping:

// an array of xml objects:
$oses = array_map(function($os) {
  return array_values((array)$os);
}, $oses);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!