excel如何读取XML文件?

时间:2014-09-23 10:06:10

标签: php xml excel

我已经研究了很多将xml文件转换为2d数组的方法与excel在excel中打开xml文件时尝试制作与excel相同的算法一样。

<items>
    <item>
        <sku>abc 1</sku>
        <title>a book 1</title>
        <price>42 1</price>
        <attributes>
            <attribute>
                <name>Number of pages 1</name>
                <value>123 1</value>
            </attribute>
            <attribute>
                <name>Author 1</name>
                <value>Rob dude 1</value>
            </attribute>
        </attributes>
        <contributors>
            <contributor>John 1</contributor>
            <contributor>Ryan 1</contributor>
        </contributors>
        <isbn>12345</isbn>
    </item>
    <item>
        <sku>abc 2</sku>
        <title>a book 2</title>
        <price>42 2</price>
        <attributes>
            <attribute>
                <name>Number of pages 2</name>
                <value>123 2</value>
            </attribute>
            <attribute>
                <name>Author 2</name>
                <value>Rob dude 2</value>
            </attribute>
        </attributes>
        <contributors>
            <contributor>John 2</contributor>
            <contributor>Ryan 2</contributor>
        </contributors>
        <isbn>6789</isbn>
     </item>
</items>

我希望它将它转换为二维数组,就像在Excel中打开相同的文件一样,它会向你显示这样的

enter image description here


我想像Excel一样转换为二维数组。到目前为止,我可以像Excel那样提取标签

function getColNames($array) {
    $cols   = array();
    foreach($array as $key=>$val) {
        if(is_array($val)) {
            if($val['type']=='complete') {
                if(in_array($val['tag'], $cols)) {

                } else {
                    $cols[] = $val['tag'];
                }
            }
         }
    }
    return $cols;
}

$p = xml_parser_create();
xml_parse_into_struct($p, $simple, $vals, $index);
xml_parser_free($p);

目标

我想让它像这样生成..

array (
    0 => array (
        'sku'=>'abc 1',
        'title'=>'a book 1',
        'price'=>'42 1',
        'name'=>'Number of Pages 1',
        'value'=>'123 1',
        'isbn'=>12345
    ),
    1 => array (
        'sku'=>'abc 1',
        'title'=>'a book 1',
        'price'=>'42 1',
        'name'=>'Author 1',
        'value'=>'Rob dude 1',
        'isbn'=>12345
    ),
    2 => array (
        'sku'=>'abc 1',
        'title'=>'a book 1',
        'price'=>'42 1',
        'contributor'=>'John 1',
        'isbn'=>12345
    ),
    3 => array (
        'sku'=>'abc 1',
        'title'=>'a book 1',
        'price'=>'42 1',
        'contributor'=>'Ryan 1',
        'isbn'=>12345
    ),
)

示例2 XML ..

 <items>
    <item>
       <sku>abc 1</sku>
       <title>a book 1</title>
       <price>42 1</price>
       <attributes>
          <attribute>
              <name>Number of pages 1</name>
              <value>123 1</value>
          </attribute>
          <attribute>
              <name>Author 1</name>
              <value>Rob dude 1</value>
          </attribute>
       </attributes>
       <contributors>
          <contributor>John 1</contributor>
          <contributor>Ryan 1</contributor>
       </contributors>
       <isbns>
            <isbn>12345a</isbn>
            <isbn>12345b</isbn>
       </isbns>
    </item>
    <item>
       <sku>abc 2</sku>
       <title>a book 2</title>
       <price>42 2</price>
       <attributes>
          <attribute>
              <name>Number of pages 2</name>
              <value>123 2</value>
          </attribute>
          <attribute>
              <name>Author 2</name>
              <value>Rob dude 2</value>
          </attribute>
       </attributes>
       <contributors>
          <contributor>John 2</contributor>
          <contributor>Ryan 2</contributor>
       </contributors>
       <isbns>
            <isbn>6789a</isbn>
            <isbn>6789b</isbn>
       </isbns>
    </item>
    </items>

示例3 XML ..

<items>
<item>
   <sku>abc 1</sku>
   <title>a book 1</title>
   <price>42 1</price>
   <attributes>
      <attribute>
          <name>Number of pages 1</name>
          <value>123 1</value>
      </attribute>
      <attribute>
          <name>Author 1</name>
          <value>Rob dude 1</value>
      </attribute>
   </attributes>
   <contributors>
      <contributor>John 1</contributor>
      <contributor>Ryan 1</contributor>
   </contributors>
   <isbns>
        <isbn>
            <name>isbn 1</name>
            <value>12345a</value>
        </isbn>
        <isbn>
            <name>isbn 2</name>
            <value>12345b</value>
        </isbn>
   </isbns>
</item>
<item>
   <sku>abc 2</sku>
   <title>a book 2</title>
   <price>42 2</price>
   <attributes>
      <attribute>
          <name>Number of pages 2</name>
          <value>123 2</value>
      </attribute>
      <attribute>
          <name>Author 2</name>
          <value>Rob dude 2</value>
      </attribute>
   </attributes>
   <contributors>
      <contributor>John 2</contributor>
      <contributor>Ryan 2</contributor>
   </contributors>
   <isbns>
        <isbn>
            <name>isbn 3</name>
            <value>6789a</value>
        </isbn>
        <isbn>
            <name>isbn 4</name>
            <value>6789b</value>
        </isbn>
   </isbns>
</item>
</items>

3 个答案:

答案 0 :(得分:3)

根据你的模糊问题,你称之为“Excel”,它用我自己的话说:它将每个/items/item元素作为一行。从文档顺序开始,column-name是每个叶元素节点的标记名,如果有重复的名称,则位置是第一个。

然后它每行创建一行,但前提是所有子元素都是叶元素。否则,将该行作为该行之外的行的基础,并插入包含非叶元素的元素。例如。如果这样的条目确实有两个具有相同名称的两个附加叶子,那么它们被插入到两行中。然后将它们的子值放入列的位置,其名称遵循第一段中描述的逻辑。

您的问题并不清楚这种逻辑的深度。所以我只把它保持在那个水平。否则,插值需要更深入地进入树中。为此,所概述的算法可能不再适合。

要在PHP中构建它,您可以特别受益于XPath,并且插值可以创建生成器

function tree_to_rows(SimpleXMLElement $xml)
{
    $columns = [];

    foreach ($xml->xpath('/*/*[1]//*[not(*)]') as $leaf) {
        $columns[$leaf->getName()] = null;
    }

    yield array_keys($columns);

    $name = $xml->xpath('/*/*[1]')[0]->getName();

    foreach ($xml->$name as $source) {
        $rowModel       = array_combine(array_keys($columns), array_fill(0, count($columns), null));
        $interpolations = [];

        foreach ($source as $child) {
            if ($child->count()) {
                $interpolations[] = $child;
            } else {
                $rowModel[$child->getName()] = $child;
            }
        }

        if (!$interpolations) {
            yield array_values($rowModel);
            continue;
        }

        foreach ($interpolations as $interpolation) {
            foreach ($interpolation as $interpolationStep) {
                $row = $rowModel;
                foreach ($interpolationStep->xpath('(.|.//*)[not(*)]') as $leaf) {
                    $row[$leaf->getName()] = $leaf;
                }
                yield array_values($row);
            }
        }
    }
}

使用它然后可以像:

一样直截了当
$xml  = simplexml_load_file('items.xml');
$rows = tree_to_rows($xml);
echo new TextTable($rows);

给出示范性输出:

+-----+--------+-----+-----------------+----------+-----------+-----+
|sku  |title   |price|name             |value     |contributor|isbn |
+-----+--------+-----+-----------------+----------+-----------+-----+
|abc 1|a book 1|42 1 |Number of pages 1|123 1     |           |12345|
+-----+--------+-----+-----------------+----------+-----------+-----+
|abc 1|a book 1|42 1 |Author 1         |Rob dude 1|           |12345|
+-----+--------+-----+-----------------+----------+-----------+-----+
|abc 1|a book 1|42 1 |                 |          |John 1     |12345|
+-----+--------+-----+-----------------+----------+-----------+-----+
|abc 1|a book 1|42 1 |                 |          |Ryan 1     |12345|
+-----+--------+-----+-----------------+----------+-----------+-----+
|abc 2|a book 2|42 2 |Number of pages 2|123 2     |           |6789 |
+-----+--------+-----+-----------------+----------+-----------+-----+
|abc 2|a book 2|42 2 |Author 2         |Rob dude 2|           |6789 |
+-----+--------+-----+-----------------+----------+-----------+-----+
|abc 2|a book 2|42 2 |                 |          |John 2     |6789 |
+-----+--------+-----+-----------------+----------+-----------+-----+
|abc 2|a book 2|42 2 |                 |          |Ryan 2     |6789 |
+-----+--------+-----+-----------------+----------+-----------+-----+

TextTable https://gist.github.com/hakre/5734770稍加修改的版本,允许在生成器上运行 - 以防您正在寻找该代码。

答案 1 :(得分:0)

为了从你给出的xml文件中获取你想要的数组,你必须这样做。这并不是太有趣,所以我希望它确实是你想要的。

鉴于您提供的确切XML,它将产生您作为最终结果的输出。

这是用php 5.6编写的。我相信你必须将函数调用移到他们自己的行,如果在你的环境中遇到问题,用array()替换[]。

$items = simplexml_load_file("items.xml");

$items_array = [];

foreach($items as $item) {

    foreach($item->attributes->attribute as $attribute) {
        array_push($items_array, itemsFactory($item, (array) $attribute));
    }

    foreach((array) $item->contributors->contributor as $contributer) {
        array_push($items_array, itemsFactory($item, $contributer));
    }

}

function itemsFactory($item, $vars) {

    $item = (array) $item;

    return [
        "sku" => $item['sku'],
        "title" => $item['title'],
        "price" => $item['price'],
        "name" => (is_array($vars) ? $vars['name'] : ""),
        "value" => (is_array($vars) ? $vars['name'] : ""),
        "contributer" => (is_string($vars) ? $vars : ""),
        "isbn" => $item['isbn']
    ];

}

var_dump($items_array);

以下是在XML文件上运行时的结果...

array(8) {
  [0]=>
  array(7) {
    ["sku"]=>
    string(5) "abc 1"
    ["title"]=>
    string(8) "a book 1"
    ["price"]=>
    string(4) "42 1"
    ["name"]=>
    string(17) "Number of pages 1"
    ["value"]=>
    string(17) "Number of pages 1"
    ["contributer"]=>
    string(0) ""
    ["isbn"]=>
    string(5) "12345"
  }
  [1]=>
  array(7) {
    ["sku"]=>
    string(5) "abc 1"
    ["title"]=>
    string(8) "a book 1"
    ["price"]=>
    string(4) "42 1"
    ["name"]=>
    string(8) "Author 1"
    ["value"]=>
    string(8) "Author 1"
    ["contributer"]=>
    string(0) ""
    ["isbn"]=>
    string(5) "12345"
  }
  [2]=>
  array(7) {
    ["sku"]=>
    string(5) "abc 1"
    ["title"]=>
    string(8) "a book 1"
    ["price"]=>
    string(4) "42 1"
    ["name"]=>
    string(0) ""
    ["value"]=>
    string(0) ""
    ["contributer"]=>
    string(6) "John 1"
    ["isbn"]=>
    string(5) "12345"
  }
  [3]=>
  array(7) {
    ["sku"]=>
    string(5) "abc 1"
    ["title"]=>
    string(8) "a book 1"
    ["price"]=>
    string(4) "42 1"
    ["name"]=>
    string(0) ""
    ["value"]=>
    string(0) ""
    ["contributer"]=>
    string(6) "Ryan 1"
    ["isbn"]=>
    string(5) "12345"
  }
  [4]=>
  array(7) {
    ["sku"]=>
    string(5) "abc 2"
    ["title"]=>
    string(8) "a book 2"
    ["price"]=>
    string(4) "42 2"
    ["name"]=>
    string(17) "Number of pages 2"
    ["value"]=>
    string(17) "Number of pages 2"
    ["contributer"]=>
    string(0) ""
    ["isbn"]=>
    string(4) "6789"
  }
  [5]=>
  array(7) {
    ["sku"]=>
    string(5) "abc 2"
    ["title"]=>
    string(8) "a book 2"
    ["price"]=>
    string(4) "42 2"
    ["name"]=>
    string(8) "Author 2"
    ["value"]=>
    string(8) "Author 2"
    ["contributer"]=>
    string(0) ""
    ["isbn"]=>
    string(4) "6789"
  }
  [6]=>
  array(7) {
    ["sku"]=>
    string(5) "abc 2"
    ["title"]=>
    string(8) "a book 2"
    ["price"]=>
    string(4) "42 2"
    ["name"]=>
    string(0) ""
    ["value"]=>
    string(0) ""
    ["contributer"]=>
    string(6) "John 2"
    ["isbn"]=>
    string(4) "6789"
  }
  [7]=>
  array(7) {
    ["sku"]=>
    string(5) "abc 2"
    ["title"]=>
    string(8) "a book 2"
    ["price"]=>
    string(4) "42 2"
    ["name"]=>
    string(0) ""
    ["value"]=>
    string(0) ""
    ["contributer"]=>
    string(6) "Ryan 2"
    ["isbn"]=>
    string(4) "6789"
  }
}

如果您实际上可以访问excel文件而不是xml,这可能会更容易。如果是这样,我们可以使用php excel来呈现完全相同的东西,但它适用于任何数据集,而不仅仅是指定的数据集。如果不是这种情况,我想不出任何其他方法将xml文件转换成你想要的。

编辑:

这也可能为主题带来更多亮点,来自PHPExcel自己的开发人员PHPExcel factory error when reading XML from URL。你可以认为你没有能够编写一些能够解析你抛出的任何XML文件的东西而不需要掌握一些Excel源代码或花费很长时间来处理这个问题。超出了这个问题的范围。但是,如果你要编写一些可以解析任何XML文件的东西,我会觉得它看起来像上面那样但是有一些TON条件。

答案 2 :(得分:0)

PHP库PHPExcel解决了您的问题:

https://phpexcel.codeplex.com/

你也可以在这里找到一些样品:

https://phpexcel.codeplex.com/wikipage?title=Examples&referringTitle=Home

https://github.com/PHPOffice/PHPExcel/wiki/User%20Documentation

它是PHP最可靠的Excel库,并且不断维护和升级。

请注意,您可以阅读(从Excel文件等)和编写(到Excel文件,PDF等)。