使用PHP将XML转换为可读CSV的实现难题
解析XML生成目标CSV的解决方案
原始XML数据
<?xml version="1.0" encoding="utf-8"?> <!-- Generated by Oracle Reports version 12.2.1.4.0 --> <REAL_ESTATE_OVERVIEW> <NAME>Mike Wazovski</NAME> <DATETIME>2022-09-23T16:30:45</DATETIME> <ESTATES> <ESTATE> <NAME>Son's house</NAME> <ROOMS> <ROOM> <ID>MH_R_01</ID> <AREA>66</AREA> </ROOM> <ROOM> <ID>MH_R_02</ID> <AREA>86</AREA> <BEDS>2</BEDS> </ROOM> </ROOMS> </ESTATE> <ESTATE> <NAME>Wife's house</NAME> <ROOMS> <ROOM> <ID>PH_R_01</ID> <AREA>75</AREA> <BEDS>2</BEDS> </ROOM> <ROOM> <ID>PH_R_02</ID> <AREA>77</AREA> </ROOM> </ROOMS> </ESTATE> </ESTATES> </REAL_ESTATE_OVERVIEW>
期望生成的CSV结构
| NAME | DATETIME | ESTATE_NAME | ROOM_ID | ROOM_AREA | ROOM_BEDS |
|---|---|---|---|---|---|
| Mike Wazovski | 2022-09-23T16:30:45 | Son's house | MH_R_01 | 66 | |
| Mike Wazovski | 2022-09-23T16:30:45 | Son's house | MH_R_02 | 86 | 2 |
| Mike Wazovski | 2022-09-23T16:30:45 | Wife's house | PH_R_01 | 75 | 2 |
| Mike Wazovski | 2022-09-23T16:30:45 | Wife's house | PH_R_02 | 77 |
原代码问题分析
你原来的递归逻辑将所有节点平铺为一维数组,没有处理XML中多重复嵌套结构(多个ESTATE、多个ROOM),无法生成对应多行的CSV数据,导致表头和行数据无法匹配目标格式。
修正后的PHP代码
$xmlStr = <<<XML <?xml version="1.0" encoding="utf-8"?> <!-- Generated by Oracle Reports version 12.2.1.4.0 --> <REAL_ESTATE_OVERVIEW> <NAME>Mike Wazovski</NAME> <DATETIME>2022-09-23T16:30:45</DATETIME> <ESTATES> <ESTATE> <NAME>Son's house</NAME> <ROOMS> <ROOM> <ID>MH_R_01</ID> <AREA>66</AREA> </ROOM> <ROOM> <ID>MH_R_02</ID> <AREA>86</AREA> <BEDS>2</BEDS> </ROOM> </ROOMS> </ESTATE> <ESTATE> <NAME>Wife's house</NAME> <ROOMS> <ROOM> <ID>PH_R_01</ID> <AREA>75</AREA> <BEDS>2</BEDS> </ROOM> <ROOM> <ID>PH_R_02</ID> <AREA>77</AREA> </ROOM> </ROOMS> </ESTATE> </ESTATES> </REAL_ESTATE_OVERVIEW> XML; $xml = simplexml_load_string($xmlStr); // 初始化表头和数据行 $headers = ['NAME', 'DATETIME', 'ESTATE_NAME', 'ROOM_ID', 'ROOM_AREA', 'ROOM_BEDS']; $rows = []; // 获取顶层固定字段 $topName = (string)$xml->NAME; $topDatetime = (string)$xml->DATETIME; // 遍历每个房产 foreach ($xml->ESTATES->ESTATE as $estate) { $estateName = (string)$estate->NAME; // 遍历每个房间 foreach ($estate->ROOMS->ROOM as $room) { $row = [ $topName, $topDatetime, $estateName, (string)$room->ID, (string)$room->AREA, (string)$room->BEDS // 不存在时自动为空字符串 ]; $rows[] = $row; } } // 输出表头和数据(或写入CSV文件) echo "<pre>"; print_r($headers); echo "</pre>"; echo "<pre>"; print_r($rows); echo "</pre>"; // 写入CSV文件示例 $fp = fopen('real_estate.csv', 'w'); fputcsv($fp, $headers); foreach ($rows as $row) { fputcsv($fp, $row); } fclose($fp);
代码逻辑说明
- 固定表头定义:直接根据目标CSV结构定义表头,避免递归带来的冗余字段
- 层级遍历:
- 先提取XML顶层的
NAME和DATETIME,作为每行的固定值 - 遍历每个
ESTATE节点,获取房产名称 - 遍历每个
ESTATE下的ROOM节点,提取房间的ID、面积、床位数
- 先提取XML顶层的
- 行数据组装:将每层字段组合为一行,不存在的字段(如部分房间的
BEDS)自动转为空字符串 - CSV输出:可直接打印数组查看结果,或通过
fputcsv写入CSV文件
内容的提问来源于stack exchange,提问作者nordictelecom
相关产品推荐
相关产品推荐

