你可以在这里划分问题。一件事是解析 HTML,这很容易用DOMDocument
and完成DOMXpath
。那是在另一个 xpath 表达式/查询的结果的上下文中运行一些映射。听起来可能有点复杂,但事实并非如此。在更简化的变体中,您可以在先前对Get parent element through xpath and all child elements的回答中找到这一点。
在您的情况下,这有点复杂,一些伪代码。我添加了标签,因为它使事情更加明显以用于演示目的:
foreach //li ::
ID := string(./@id)
ParentID := string(./ancestor::li[1]/@id)
Label := normalize-space(./text()[1])
如图所示,这仅返回裸数据。你也有骑士团和孩子们。通常不需要儿童列表(无论如何我都保留在这里)。Order 值和 Children 值之间的相似之处在于它们是从上下文中检索的。
例如,//li
在按文档顺序遍历节点列表时,如果每个 ParentID 都保留一个计数器,则可以对每个子节点的顺序进行编号。
与 Children 类似,就像计数器一样,需要在迭代列表时构建该值。只有在最后,每个列表项的正确值才可用。
所以这两个值在一个上下文中,我以 ParentID: 键控的数组的形式创建该上下文$parents
。对于每个 ID,它将包含两个条目:0 包含 Order 的计数器,1 包含一个数组以保存 Children 的 ID(如果有)。
注意:从技术上讲,这并不完全正确。Order 和 Children 也应该可以在纯 xpath 中表达,我只是在这个示例中没有这样做来展示如何添加您自己的非 xpath 上下文,例如,如果您想要不同的 ordering 或 children 处理。
理论就够了。考虑标准设置:
$doc = new DOMDocument();
$doc->loadHTML($html);
$xp = new DOMXPath($doc);
所述映射包括。它的上下文可以写成匿名函数:
$parents = [];
$map = function (DOMElement $li) use ($xp, &$parents) {
$id = (int)$xp->evaluate('string(./@id)', $li);
$parentId = (int)$xp->evaluate('string(./ancestor::li[1]/@id)', $li);
$label = $xp->evaluate('normalize-space(./text()[1])', $li);
isset($parents[$parentId][0]) ? $parents[$parentId][0]++ : ($parents[$parentId][0] = 1);
$order = $parents[$parentId][0];
$parents[$parentId][1][] = $id;
isset($parents[$id][1]) || $parents[$id][1] = [];
return array($id, $label, $order, $parentId, &$parents[$id][1]);
};
如您所见,它首先包含对伪代码中的值的检索,第二部分包含对上下文值的处理。如果 ID / ParentID 不存在,它只是初始化上下文。
需要应用此映射:
$result = [];
foreach ($xp->query('//li') as $li) {
list($id) = $array = $map($li);
$result[$id] = $array;
}
这将$result
包含项目列表和$parents
上下文数据。由于使用了引用,现在需要对 Children 值进行内爆,然后可以删除引用:
foreach ($parents as &$parent) {
$parent[1] = implode(',', $parent[1]);
}
unset($parent, $parents);
这会$result
产生可以输出的最终结果:
echo '+----+----------------+-------+--------+----------+
| ID | LABEL | ORDER | PARENT | CHILDREN |
+----+----------------+-------+--------+----------+
';
foreach ($result as $line) {
vprintf("| %' 2d | %' -14s | %' 2d | %' 2d | %-8s |\n", $line);
}
echo '+----+----------------+-------+--------+----------+
';
然后看起来像:
+----+----------------+-------+--------+----------+
| ID | LABEL | ORDER | PARENT | CHILDREN |
+----+----------------+-------+--------+----------+
| 1 | Page 1 | 1 | 0 | |
| 2 | Page 2 | 2 | 0 | 3,4,5 |
| 3 | Sub Page A | 1 | 2 | |
| 4 | Sub Page B | 2 | 2 | |
| 5 | Sub Page C | 3 | 2 | 6 |
| 6 | Sub Sub Page I | 1 | 5 | |
| 7 | Page 3 | 3 | 0 | 8 |
| 8 | Sub Page D | 1 | 7 | |
| 9 | Page 4 | 4 | 0 | |
+----+----------------+-------+--------+----------+
您可以在此处在线找到演示。