如何在PHP中将包含CDATA的大体积XML文件转换为JSON格式
PHP处理WordPress WXR格式XML转JSON的完整解决方案
问题根源
- SimpleXML默认不会自动加载带前缀的命名空间节点(如
wp:wxr_version、wp:author等WXR专用节点),需要手动指定命名空间提取 - 直接对SimpleXMLElement对象执行
json_encode()只会序列化默认层的属性,嵌套内容、CDATA节点容易丢失,哪怕开启LIBXML_NOCDATA也无法覆盖命名空间内的CDATA内容
可直接使用的实现代码
<?php // 定义要加载的WXR文件路径 $xmlPath = 'belovedskincare.xml'; // 第一步:加载XML,保留CDATA $xml = simplexml_load_file($xmlPath, 'SimpleXMLElement', LIBXML_NOCDATA); // 第二步:注册WXR常用的命名空间,可根据实际导出文件的命名空间补充 $namespaces = $xml->getDocNamespaces(true); $xml->registerXPathNamespace('wp', $namespaces['wp']); $xml->registerXPathNamespace('excerpt', $namespaces['excerpt'] ?? ''); $xml->registerXPathNamespace('content', $namespaces['content'] ?? ''); // 第三步:自定义递归转换函数,提取所有节点包括命名空间节点 function xml_to_object($xml, $namespaces) { $data = []; // 处理当前节点的属性 foreach ($xml->attributes() as $attrKey => $attrVal) { $data['@attributes'][$attrKey] = (string)$attrVal; } // 处理默认命名空间的子节点 foreach ($xml->children() as $nodeKey => $nodeVal) { if (count($nodeVal->children()) > 0) { $data[$nodeKey][] = xml_to_object($nodeVal, $namespaces); } else { $data[$nodeKey] = (string)$nodeVal; } } // 处理所有带命名空间的子节点 foreach ($namespaces as $nsPrefix => $nsUri) { if (empty($nsPrefix)) continue; foreach ($xml->children($nsUri) as $nodeKey => $nodeVal) { if (count($nodeVal->children()) > 0) { $data[$nsPrefix . ':' . $nodeKey][] = xml_to_object($nodeVal, $namespaces); } else { $data[$nsPrefix . ':' . $nodeKey] = (string)$nodeVal; } } } return $data; } // 执行转换 $fullData = xml_to_object($xml, $namespaces); // 输出JSON,JSON_UNESCAPED_UNICODE保证中文不转义 $jsonData = json_encode($fullData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); echo $jsonData; // 如果需要保存到文件可以加下面这句 // file_put_contents('wxr_export.json', $jsonData); ?>
大体积XML优化提示
如果导出的WXR文件超过100M,建议改用XMLReader逐段解析加载,避免内存溢出,核心逻辑和上面的转换函数一致,只是把一次性加载改为逐节点读取处理。
内容的提问来源于stack exchange,提问作者Senthur Kumaran
相关产品推荐
相关产品推荐

