php - PHP 遍历具有无效结构的 XML 文件
问题描述
如何遍历如下所示的 XML 文件?它的输出没有任何根节点或父节点。有些元素会重复,但有些则不会。而且,它是来自遗留应用程序的大文件输出。
<name>Chair</name>
<price>$53</price>
<quantity>20</quantity>
<units>Piece</units>
<name>Lamp</name>
<price>$20</price>
<quantity>90</quantity>
<units>Piece</units>
<name>Table</name>
<price>$35</price>
<quantity>10</quantity>
<units>Piece</units>
<material>Wood</material>
<name>Pen Holder</name>
<price>$5</price>
<quantity>20</quantity>
<units>Piece</units>
<color>Black</color>
否则我就是这样做的,但它不适用于此。
$data=simplexml_load_file("inventory.xml");
foreach($data->item as $item) {
echo "Name: " . $item->name . "<br>";
echo "Price: " . $item->price . "<br>";
echo "Quantity: " . $item->quantity . "<br>";
echo "Units: " . $item->units . "<br>";
echo "Color: " . $item->color . "<br>";
}
解决方案
添加根元素很容易。您只需将 XML 加载到字符串中,然后根据需要附加和前置。但是,对项目中的各种元素进行分组有点棘手,并且很大程度上取决于 XML。以下代码将适用于您显示的 XML:
<?php
$xml = 'your xml from the question';
$dom = new DOMDocument;
$dom->loadXml("<root>$xml</root>");
$fixed = new DOMDocument();
$fixed->loadXML("<inventory><items/></inventory>");
$fixed->formatOutput = true;
$items = $fixed->getElementsByTagName('items')->item(0);
foreach ($dom->documentElement->childNodes as $node) {
if ($node->nodeName === 'name') {
$item = $fixed->createElement('item');
$item->appendChild($fixed->createElement($node->nodeName, $node->nodeValue));
$next = $node->nextSibling;
while ($next !== null) {
if ($next instanceof DOMElement) {
if ($next->nodeName !== 'name') {
$item->appendChild($fixed->createElement($next->nodeName, $next->nodeValue));
} else {
$items->appendChild($item);
break;
}
}
$next = $next->nextSibling;
}
}
}
echo $fixed->saveXML();
这将创建两个文档:
- 您的旧 XML 带有一个虚拟
<root>
元素,因此我们可以对其进行处理 - 具有根元素
<inventory>
和空元素的文档<items>
。
然后我们将迭代遗留 XML 中的所有元素。当我们找到一个<name>
元素时,我们创建一个新<item>
元素并将该<name>
元素添加为子元素。然后我们检查<name>
元素的每个后续兄弟。如果它不是一个<name>
元素,我们也会将它添加到<item>
。当它是另一个<name>
时,我们将其添加<item>
到<items>
集合中并重新开始。
这将产生:
<?xml version="1.0"?>
<inventory>
<items>
<item>
<name>Chair</name>
<price>$53</price>
<quantity>20</quantity>
<units>Piece</units>
</item>
<item>
<name>Lamp</name>
<price>$20</price>
<quantity>90</quantity>
<units>Piece</units>
</item>
<item>
<name>Table</name>
<price>$35</price>
<quantity>10</quantity>
<units>Piece</units>
<material>Wood</material>
</item>
</items>
</inventory>
您可能可以在一个文档中完成所有这些操作。我觉得用两个文件更容易理解。
推荐阅读
- javascript - Onclick 函数在加载事件侦听器中时未调用
- sharepoint - 如何开始从 SharePoint 外部读取 SharePoint 列表信息?
- python - 将两个单独的数据框之间的对应列组合成新的数据框
- ios - 视图转换后如何修复不均匀的边框宽度?
- angularjs - 如何为自定义 B2C 邀请策略注册 MSAL JS 回调?
- flutter - WidgetsApp 类、MaterialApp 类和 Directionality 类有什么区别
- python - 当复杂索引和基于布尔的条件作为子集时,如何为熊猫数据框赋值?
- yii - Yii 2 高级模板默认后台管理员登录详情
- javascript - 如果在使用 javascript 中的 map 方法通过该数组执行循环期间将元素推入数组会发生什么
- javascript - 如何按 id 更新索引对象数组