使用simplexml解析xml文件并使用php创建具有命名键(不是数字键)的数组

时间:2014-05-07 13:13:34

标签: php xml multidimensional-array simplexml

我已经使用带有数字键的simplexml从已解析的xml文件创建了多维数组,但我希望它们被命名为键而不是数字。

xml文件如下:

<workbook  xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" >
<Worksheet ss:Name="tab1">
<Table>
   <Row>
        <Cell><Data>Id</Data></Cell>   // names which i want to be array keys. 
        <Cell><Data>Company</Data></Cell>  //
        <Cell><Data>Year</Data></Cell>    //
   </Row>
   <Row>
        <Cell><Data>120</Data></Cell>   //values 
        <Cell><Data>Apple</Data></Cell>
        <Cell><Data>2011</Data></Cell>
   </Row>
   <Row>
        <Cell><Data>121</Data></Cell>
        <Cell><Data>Samsung</Data></Cell>
        <Cell><Data>2010</Data></Cell>
   </Row>
</Table>
</Worksheet>
<Worksheet ss:Name="tab2">
 <Table>
    <Row>
        <Cell><Data>Id</Data></Cell>      
        <Cell><Data>Company</Data></Cell>   
        <Cell><Data>Year</Data></Cell>
   </Row>
   <Row>
       <Cell><Data>320</Data></Cell>  
       <Cell><Data>Sony</Data></Cell>
       <Cell><Data>2001</Data></Cell> 
   </Row>
   <Row>
       <Cell><Data>321</Data></Cell>
       <Cell><Data>HTC</Data></Cell>
       <Cell><Data>2001</Data></Cell> 
   </Row> 
  </Table>
</Worksheet>
</workbook>

她是我解析xml文件和创建数组的代码

$xml=simplexml_load_file($fileData);
$result= array();
$i=0;
foreach($xml->Worksheet as $worksheet ):
  $result['tab'][$i] = array();
  $result['tab'][$i]['name']=(string)$worksheet->attributes("ss", true)->Name;
  foreach($worksheet as $table):
    $k =0;
    unset($table->Row[0]); //removing first row which i want to be keys of array
    foreach($table as $row):
      foreach($row as  $cell):
         $result['tab'][$i]['data'][$k][] =(string)$cell->Data;
      endforeach;
      $k++;
    endforeach;
  endforeach;
  $i++;
endforeach;
return $result;

我得到的数组:

  Array
  (
  [tab] => Array
    (
        [0] => Array
            (
                [name] => tab1
                [data] => Array
                    (
                        [0] => Array
                            (
                                [0] => 120   //keys should be name of first row of xml 
                                [1] => Apple
                                [2] => 2011
                            )

                        [1] => Array
                            (
                                [0] => 121
                                [1] => Samsung
                                [2] => 2010
                            )

                    )

            )

        [1] => Array
            (
                [name] => tab2
                [data] => Array
                    (
                        [0] => Array
                            (
                                [0] => 320
                                [1] => Sony
                                [2] => 2001
                            )

                        [1] => Array
                            (
                                [0] => 321
                                [1] => HTC
                                [2] => 2001
                            )

                    )

            )

    )

)

我希望数组如下:

  Array
 (
  [tab] => Array
    (
        [0] => Array
            (
                [name] => tab1
                [data] => Array
                    (
                        [0] => Array
                            (
                                [Id] => 120          // named keys instead of numbers
                                [Company] => Apple
                                [Year] => 2011
                            )

                        [1] => Array
                            (
                                [Id] => 121
                                [Company] => Samsung
                                [Year] => 2010
                            )

                    )

            )

        [1] => Array
            (
                [name] => tab2
                [data] => Array
                    (
                        [0] => Array
                            (
                                [Id] => 320
                                [Company] => Sony
                                [Year] => 2001
                            )

                        [1] => Array
                            (
                                [Id] => 321
                                [Company] => HTC
                                [Year] => 2001
                            )

                    )

            )

    )

这是一个有点长的问题。但很好解释。 谢谢。

1 个答案:

答案 0 :(得分:3)

将每个表行转换为数组,然后将第一行用作后续行的键:

$table_to_array = function(SimpleXMLElement $table) {
    $keyed = function($table) {
        $keys = NULL;
        foreach ($table->Row as $row) {
            $array = array_map('trim', $row->xpath('Cell/Data'));
            $keys  ? (yield array_combine($keys, $array))
                : $keys = $array;
        }
    };
    return iterator_to_array($keyed($table));
};

$xml = simplexml_load_file($path_to_xml_file);

$array = $table_to_array($xml->Worksheet->Table);

print_r($array);

输出:

Array
(
    [0] => Array
        (
            [Id] => 120
            [Company] => Apple
            [Year] => 2011
        )

    [1] => Array
        (
            [Id] => 121
            [Company] => Samsung
            [Year] => 2010
        )

)

将它应用于任意数量的表格。


如果你有PHP&lt; 5.5然后你还不能使用Generators,但是,你仍然可以使用迭代器。这或多或少只意味着您需要编写更多代码:

// this example uses some code from:
// https://github.com/hakre/Iterator-Garden/blob/master/src/IndexIteration.php
require_once 'IndexIteration.php';

class TableRowIterator extends IteratorIterator
{
    public function __construct(SimpleXMLElement $table) {
        parent::__construct(new IndexIteration($table->Row));
    }

    public function current() {
        return array_map('trim', parent::current()->xpath('Cell/Data'));
    }

    public function key() {
        return $this->getInnerIterator()->getIndex();
    }
}

class KeyedArrayIterator extends IteratorIterator
{
    private $keys;

    public function rewind()
    {
        parent::rewind();
        $this->keys = parent::current();
        parent::next();
    }

    public function current()
    {
        return array_combine($this->keys, parent::current());
    }
}

$table_to_array = function($table) {
    $rows  = new TableRowIterator($table);
    $keyed = new KeyedArrayIterator($rows);
    return iterator_to_array($keyed);
};

$xml = simplexml_load_file($path_to_xml_file);

$array = $table_to_array($xml->Worksheet->Table);

print_r($array);

正如它所示,更多的代码行,但处理数据的方式相同。将KeyedArrayIteratorthe commented answer中的CSVFile Iterator类进行比较,就是这种处理方式:将第一行用作所有后续行的键。

输出与使用生成器的PHP 5.5示例完全相同。