【问题标题】:Add Child to XML Then Convert to CSV将子项添加到 XML 然后转换为 CSV
【发布时间】:2013-07-05 20:23:50
【问题描述】:

基本上我有一个可以转换为 CSV 的 XML 文件。这很好用,但我需要修改它以将相同的子元素添加到每个 XML 父元素,然后再将其转换为 CSV。我似乎只能将其添加到第一个元素中,仅此而已。有没有办法自动将同一个子元素添加到 XML 文件中的所有元素?

这里是 XML

我有成千上万个。

<Item>
  <product>test</product>
  <Image>AC45G.jpg</Image>
</Item>

这是我的代码

<?php

$new_xml = simplexml_load_file('test.xml');

    $items = $new_xml->Item;

    $items->addChild('distributor', 'test');

function outputCSV($new_xml) {
    $outstream = fopen("php://output", 'w');
    $header=false;
    foreach($new_xml as $k=>$details){

        if(!$header){
            fputcsv($outstream,array_keys(get_object_vars($details)));
            $header=true;
        }
        fputcsv($outstream,get_object_vars($details));
    }
fclose($outstream);  
}


    header("Content-type: text/csv");
    header("Content-Disposition: attachment; filename=lipseys.csv");
    header("Pragma: no-cache");
    header("Expires: 0");

    outputCSV($new_xml);
?>

【问题讨论】:

  • 循环遍历 $items 并将其添加到它的所有子元素中?

标签: php xml csv


【解决方案1】:

默认情况下,SimpleXML 会遍历 SimpleXMLElement 的所有子元素,因此您需要在根元素上使用 foreach(在以下示例中名为 $element 而不是您的问题中的 $new_xml),然后将新的孩子添加到它的每个孩子:

// iterate over child elements
foreach ($element as $child)
{
    $child->addChild('distributor', 'test');
}

SimpleXMLElement::children() 方法的区别在于,它将使用SimpleXMLElement命名空间,而不是@987654329 中给定的命名空间(可选) @方法。

您可以通过在加载文件或实例化 SimpleXMLElement 时指定默认命名空间来更改迭代的默认命名空间。另见:What are the “$ns” and “$is_prefix” parameters about?

用法示例:

$xml = simplexml_load_file('test.xml');

$items = $xml;

foreach ($items as $item) {
    $item->addChild('distributor', 'test: ' . $item);
}

header("Content-type: text/csv");
header("Content-Disposition: attachment; filename=lipseys.csv");
header("Pragma: no-cache");
header("Expires: 0");

$file = new SplFileObject("php://output");
foreach (new ValuesWithHeadersIterator($items) as $values) {
    $file->fputcsv($values);
}

使用的迭代器:

/**
 * Class ValuesIterator
 *
 * Treats each iteration as being (or being cast-able) to an array
 * of values.
 */
class ValuesIterator extends IteratorIterator
{
    public function current() {
        return (array) parent::current();
    }
}

/**
 * Class KeysIterator
 *
 * Returns keys instead of values per each ValuesIterator iteration.
 */
class KeysIterator extends ValuesIterator
{
    public function current() {
        return array_keys(parent::current());
    }
}


/**
 * Class ValuesWithHeadersIterator
 *
 * Same as ValuesIterator but expecting the first values
 * to have keys that can be used as headers
 */
class ValuesWithHeadersIterator extends IteratorIterator
{
    public function __construct(Traversable $iterator) {
        $headers = new LimitIterator(new KeysIterator($iterator), 0, 1);
        $values  = new ValuesIterator($iterator);
        $append  = new AppendIterator();
        $append->append($headers);
        $append->append($values);
        parent::__construct($append);
    }
}

【讨论】:

    【解决方案2】:

    也许像这样使用 children() 和 foreach

    <?php
    foreach ($new_xml ->children() as $second_gen){
      $second_gen->addChild('distributor', 'test');
    }
    ?>
    

    【讨论】:

    • 但只是可能。实际上更重要的是foreachchildren() 实际上是默认迭代,因此您可以省去该方法调用。
    猜你喜欢
    • 1970-01-01
    • 2022-12-07
    • 2017-03-29
    • 2013-06-20
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    相关资源
    最近更新 更多