DomDocument removeChild在foreach中重新索引dom
DomDocument removeChild in foreach reindexing the dom
我正在尝试删除具有data-spotid
属性的p
标签
$dom = new DOMDocument();
@$dom->loadHTML($description);
$pTag = $dom->getElementsByTagName('p');
foreach ($pTag as $value) {
/** @var DOMElement $value */
$id = $value->getAttribute('data-spotid');
if ($id) {
$value->parentNode->removeChild($value);
}
}
但当我移除child时,它正在重新索引dom。假设我删除了8个项目,第一个它将重新索引它,第二个元素将成为第一个,它不会删除它,它将转到第二个,现在是第三个元素。
DomNode::removeChild
文档上的几条注释中提到了这一点,问题显然是foreach上的迭代器指针无法处理在循环子数组(或其他)时从父数组中删除项的事实。
建议的修复方法是首先循环遍历主节点,并将要删除的子节点推送到其自己的数组中,然后循环遍历"待删除"数组,并从其父节点中删除这些子节点。示例:
$dom = new DOMDocument();
@$dom->loadHTML($description);
$pTag = $dom->getElementsByTagName('p');
$spotid_children = array();
foreach ($pTag as $value) {
/** @var DOMElement $value */
$id = $value->getAttribute('data-spotid');
if ($id) {
$spotid_children[] = $value;
}
}
foreach ($spotid_children as $spotid_child) {
$spotid_child->parentNode->removeChild($spotid_child);
}
我们可以这样使用:
$dom = new DOMDocument();
@$dom->loadHTML($description);
$pTag = $dom->getElementsByTagName('p');
$count = count($pTag)
for($i = 0; $i < $count; $i++) {
/** @var DOMElement $value */
$value = $pTag[$i];
$id = $value->getAttribute('data-spotid');
if ($id) {
$i--;$count--;
$value->parentNode->removeChild($value);
}
}
正如我所评论的,简单的解决方案是将迭代器强制转换为数组。例如:
$elements = iterator_to_array($elements);
但是,如果我们谈论性能,更好的方法是只选择所需的节点。整洁的副作用,去除问题也消失了。
例如:
<?php
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->loadXML(<<<__XML
<?xml version="1.0" encoding="UTF-8"?>
<root>
<element>1</element>
<element attr="a">2</element>
<element>3</element>
<element>4</element>
<element attr="a">5</element>
<element attr="a">6</element>
<element>7</element>
<element>8</element>
</root>
__XML
);
$xpath = new DOMXPath($doc);
$elements = $xpath->query('//element[@attr]');
foreach ($elements as $element) {
$element->parentNode->removeChild($element);
}
echo $doc->saveXML();
演示:https://3v4l.org/CM9Fv
(假设$dom包含需要过滤掉的(dom)段落)。让我们试试一些好的老JavaScript:
$ptag = $dom.all.tags("p");
$ptag = [].slice.call($ptag);
$i = 0;
while($ptag[$i]){
'data-spotid' in $ptag[$i].attributes ? $ptag[$i++].outerHTML = "" : 0
}
注意:我使用outerHTML来销毁不需要的元素,以避免调用它的父节点和重新定位我们已经拥有的感兴趣的节点。最近的Firefox版本终于支持它了(11+)。MDN ref
为了简洁起见,我还使用了shortall.tags()语法;Firefox可能还不支持它,所以您可能想回到"getElementsByTagName()"调用。
相关文章:
- 名称输入的索引
- 在单击任何位置时隐藏元素,而不检查每次DOM单击
- 在jQuery中获取表的行索引
- 触发具有较低Z索引值的DOM元素的事件
- DomDocument removeChild在foreach中重新索引dom
- JavaScript DOM:在容器中查找元素索引
- 如何通过知道节点的值来访问dom&&只要知道价值就可以得到手风琴的索引
- 获取所选元素的位置,而不是 DOM 中元素的索引
- 索引数据库与DOM有什么关系吗?
- 当 Angular 索引页面加载到 DOM [Angular 模板到静态 HTML] 中时,我可以拍摄它的纯 HTML
- 获取所选 DOM 元素的索引,返回 -1
- 如何表征DOM的z索引?(2)
- 在基于DOM元素而非索引的引导旋转木马中跳到另一张幻灯片
- 将搜索引擎索引DOM生成的HTML
- 在HTML表行DOM元素中查找行索引
- 使用索引从jQuery数组返回jQuery对象(而不是DOM)
- 根据选择查找dom索引
- 使用jQuery设置动态下拉列表(DOM)的选定索引
- 索引dom元素
- 为多类元素中某一类的元素查找Dom节点索引