解析XML文件时如何生成元素完整路径并统计元素数量
问题描述
我通过以下代码加载XML文件:
$xml = simplexml_load_file('http://example.com');
对应的XML内容为:
<shop> <name>Shop name</name> <company>Company name</company> <url>https://example.com/shop</url> <url>https://example.com/shop2</url> <url>https://example.com/shop3</url> <currencies> <currency> <name>XXX</name> </currency> <currency> <name>YYY</name> </currency> <currency> <name>ZZZ</name> </currency> </currencies> </shop>
我原本用这段代码统计所有元素的名称和数量:
$elements = []; foreach ($xml->xpath('//*') as $element) { $name = $element->getName(); $elements[$name] = ($elements[$name] ?? 0) + 1; }
得到的结果是:
[ 'shop' => 1, 'name' => 4, 'company' => 1, 'url' => 3, 'currencies' => 1, 'currency' => 3 ]
现在需要修改代码,让结果数组同时包含元素的完整路径(从根节点开始的层级路径),期望结构如下:
[ 'shop' => [ 'count' => 1, 'path' => 'shop', ], 'name' => [ 'count' => 4, 'path' => 'shop.name', ], 'company' => [ 'count' => 1, 'path' => 'shop.company', ], 'url' => [ 'count' => 3, 'path' => 'shop.url', ], 'currencies' => [ 'count' => 1, 'path' => 'shop.currencies', ], 'currency' => [ 'count' => 3, 'path' => 'shop.currencies.currency', ] ]
解决方案
以下是修改后的代码,可实现需求:
$elements = []; foreach ($xml->xpath('//*') as $element) { $elementName = $element->getName(); // 获取当前元素的所有祖先及自身节点,按根到当前的顺序排列 $pathNodes = $element->xpath('ancestor-or-self::*'); $pathParts = []; foreach ($pathNodes as $node) { $pathParts[] = $node->getName(); } $fullPath = implode('.', $pathParts); // 初始化或更新统计数据 if (!isset($elements[$elementName])) { $elements[$elementName] = [ 'count' => 0, 'path' => $fullPath ]; } $elements[$elementName]['count']++; }
代码说明
- 生成完整路径:通过
xpath('ancestor-or-self::*')获取当前元素的所有祖先节点(包括自身),遍历这些节点收集名称后用.拼接成层级路径。 - 分组统计:以元素名称为键,初始化包含
count和path的数组,每遇到同名元素就将count加1。注意:若XML中存在同名但路径不同的元素(比如不同层级的name),此代码会合并统计数量,路径保留第一个出现的元素路径;若需区分不同路径的同名元素,需将路径作为数组键而非元素名称。
内容的提问来源于stack exchange,提问作者Rediska
相关产品推荐
相关产品推荐

