Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用PHP将XML转换为CSV,但有点扭曲_Php_Xml_Csv_Simplexml - Fatal编程技术网

使用PHP将XML转换为CSV,但有点扭曲

使用PHP将XML转换为CSV,但有点扭曲,php,xml,csv,simplexml,Php,Xml,Csv,Simplexml,我正在尝试使用PHP SimpleXML类将一些XML文件转换为CSV。但是,我无法实现我想要的结果,因为一个父元素可以有几个同名的子元素。我当前的XML文件如下所示: <?xml version="1.0" encoding="UTF-8"?> <root> <club> <name>Green Riders</name> <membership>Free</membersh

我正在尝试使用PHP SimpleXML类将一些XML文件转换为CSV。但是,我无法实现我想要的结果,因为一个父元素可以有几个同名的子元素。我当前的XML文件如下所示:

<?xml version="1.0" encoding="UTF-8"?>

<root>
    <club>
        <name>Green Riders</name>
        <membership>Free</membership>
        <boardMember>
            <name>James F.</name>
            <position>CEO</position>
        </boardMember>
        <boardMember>
            <name>Helen D.</name>
            <position>Associate Director</position>
        </boardMember>
    </club>
    <club>
        <name>Broken Dice</name>
        <membership>Paid</membership>
        <boardMember>
            <name>Patrick B.</name>
            <position>CEO</position>
        </boardMember>
    </club>    
</root>
在不将元素名称硬编码到脚本中的情况下(即,使其在任何通用XML文件上工作),是否可以实现这一点

我真的希望这是可能的,因为我将有超过25个XML变体;因此,为每个脚本编写一个专用脚本是非常低效的。
谢谢

由于每个子节点的数据都需要是csv中的一行,包括根数据,因此首先可以捕获并存储根数据,然后遍历子节点并打印其数据,其中根数据位于子节点之前

请检查以下代码:

$xml = simplexml_load_file("your_xml_file.xml") or die("Error: Cannot create object");

$csv_delimeter = ",";
$csv_new_line = "\n";

foreach($xml->children() as $n) {
    $club_data = array();
    $club_data[] = $n->name;
    $club_data[] = $n->membership;

    if (isset($n->boardMember)) {
        foreach ($n->boardMember as $boardMember) {
            $boardMember_data = $club_data;
            $boardMember_data[] = $boardMember->name;
            $boardMember_data[] = $boardMember->position;

            echo implode($csv_delimeter, $boardMember_data).$csv_new_line;
        }
    }
    else {
        echo implode($csv_delimeter, $club_data).$csv_new_line;
    }
}
在使用示例xml数据进行测试后,它生成了以下类型的输出:

Green Riders,Free,James F.,CEO
Green Riders,Free,Helen D., Associate Director
Broken Dice,Paid,Patrick B., CEO
您可以根据您的场景为以下各项设置不同的值:

$csv_delimeter = ",";
$csv_new_line = "\n";
由于csv输出中没有严格的规则,例如delimeter可以是“、”、“、”、“;”或“|”,新行也可以是“\n\r”


代码会动态地逐个打印csv行,但如果要将csv数据保存在文件中,则更好的方法不是逐个写入行,而是创建整个阵列并写入一次(因为磁盘访问成本很高),除非xml数据很大。您将在网上获得大量简单的php数组到csv函数示例。

这实际上是不可能的。XML是一种嵌套结构,您会丢失信息。您可以为XML结构定义一些默认映射,但这很快就会变得非常复杂。因此,手动定义映射要容易得多(而且耗时更少)

可重复使用的转换 映射 使用
DOMXpath::evaluate()
Xpath表达式可以返回字符串。因此,我们需要一个返回
boardMember
节点的表达式和字段的表达式列表

$map = [
  'row' => '/root/club/boardMember',
  'columns' => [
    'club_name' => 'string(parent::club/name)',
    'club_membership' => 'string(parent::club/membership)',
    'board_member_name' => 'string(name)',
    'board_member_position' => 'string(position)'
  ]
];
到CSV
readXMLAsRecords()
返回一个生成器,您可以对其使用
foreach

$csv = fopen('php://stdout', 'w');
fputcsv($csv, array_keys($map['columns']));
foreach (readXMLAsRecords($xml, $map) as $record) {
  fputcsv($csv, $record);
}
输出:

club_name,club_membership,board_member_name,board_member_position
"Green Riders",Free,"James F.",CEO
"Green Riders",Free,"Helen D.","Associate Director"
"Broken Dice",Paid,"Patrick B.",CEO

虽然这可能会解决问题,但最好在解决问题的同时说明您的一般方法。这有助于有类似问题的人根据自己的需要调整解决方案。谢谢@IMSoP!我已经详细说明了答案。如果我遗漏了什么,请随意添加:)是否可以保证只有一个重复的名称,或者您可能需要生成多个列的所有可能组合?e、 g.
12abc
是否应该为
1、a
1、b
1、c
2、a
2、b
2、c
生成一个包含
foo、bar
列和6行的CSV?我突然想到,这就是创建XSLT的任务类型,我花了一点时间才意识到,关键是“行”表达式针对的是一名董事会成员,而其他表达式则向上爬升以获取其他数据。由于我的评论从未得到回答,这是对问题的合理解释,但如果涉及更复杂的组合,则需要更复杂的算法。不过,我绝对同意,编写一个接受定义的工具比尝试创建一个能够处理所有结构的零配置算法要好。
$csv = fopen('php://stdout', 'w');
fputcsv($csv, array_keys($map['columns']));
foreach (readXMLAsRecords($xml, $map) as $record) {
  fputcsv($csv, $record);
}
club_name,club_membership,board_member_name,board_member_position
"Green Riders",Free,"James F.",CEO
"Green Riders",Free,"Helen D.","Associate Director"
"Broken Dice",Paid,"Patrick B.",CEO