PHPDom遍历文档并删除没有XPath的节点
我试图遍历一个文档,并删除节点(在我的例子中是所有div),但没有xpath(我已经可以用xpath完成这项工作)。由于某些原因,只有第一个div被删除。有什么建议吗PHPDom遍历文档并删除没有XPath的节点,php,dom,xpath,domdocument,Php,Dom,Xpath,Domdocument,我试图遍历一个文档,并删除节点(在我的例子中是所有div),但没有xpath(我已经可以用xpath完成这项工作)。由于某些原因,只有第一个div被删除。有什么建议吗 <?php //my totally random html $html = '<p> Great <div> dont want this</div> </p><p> some more</p><div>more crap
<?php
//my totally random html
$html = '<p> Great <div> dont want this</div> </p><p> some more</p><div>more crap here</div>';
$doc = new DOMDocument();
$doc->loadHTML($html);
iterate_children($doc );
print $doc->saveHTML();
function iterate_children(&$object){
//print_r($object);
if ($object->tagName == "div") {
$object->parentNode->removeChild($object);
iterate_children($object->parentNode);
}
else {
//if($object->hasChildNodes()) {
foreach($object->childNodes as $child) {
//
iterate_children($child);
//}
}
}
}
?>
删除第一个div的原因可能最简单的解释如下: 迭代所有子节点。此迭代首先将当前节点设置为第一个子节点()。然后处理该子项,完成后继续处理下一个子项(即) 但是如果现在从父节点中删除当前节点
$object->parentNode->removeChild($object);
迭代中的当前节点不再有任何下一个同级节点(因为它已从其父节点中删除)。因此,foreach迭代在删除第一个div元素后立即结束
有不同的方法来解决这个问题。使用纯PHP且不使用任何xpath,可以先将要删除的所有节点存储在一个数组中,然后删除它们。该功能在以下情况下非常方便:
$divs = iterator_to_array($doc->getElementsByTagName('div'));
foreach ($divs as $div) {
$div->parentNode->removeChild($div);
}
这四行代码确实替换了(不工作的)函数(!)的所有迭代和递归逻辑
您还可以通过在迭代当前元素(缓存当前元素)时使用内部已包含下一个元素的来修复函数。它不会失效,因为从父节点移除当前节点的那一刻,下一个节点已经被获取
大致用于更改以下行的代码:
foreach($object->childNodes as $child) {
iterate_children($child);
}
致:
但请注意,此代码仅用于演示目的。如果您将其复制并粘贴到示例中,它将崩溃,因为您的代码中存在一些其他问题,这些问题将随着这样的更改而变得严重
这段代码仍然具有实际上不需要的递归,因为您可以按文档顺序迭代节点。为此,我有一个域节点编辑器。该库中还有一个简单的DOMElementFilter。由于下一个兄弟姐妹的问题在这里是相同的,因此使用这两个兄弟姐妹还需要一个cachingierator:
$divs = new CachingIterator(new DOMElementFilter(new DOMNodeIterator($doc), 'div'), CachingIterator::TOSTRING_USE_KEY);
foreach ($divs as $div) {
$div->parentNode->removeChild($div);
}
这段代码与迭代器-to-array
示例非常相似。由于迭代器的装饰性,它通常使您能够创建更多可重用的代码
我希望这有助于您理解为什么会发生这种情况,并展示了一些处理方法
出于完整性的考虑,以下是具有更好错误处理和遍历逻辑的代码:
function iterate_children(DOMNode $node)
{
if ($node instanceof DOMElement and $node->tagName == "div") {
$parent = $node->parentNode;
$parent->removeChild($node);
return;
}
$children = $node->childNodes;
if (!$children) {
return;
}
$children = new IteratorIterator($children);
$children = new CachingIterator($children, CachingIterator::TOSTRING_USE_KEY);
foreach ($children as $child) {
iterate_children_old($child);
}
}
这里是不使用递归和数组的实现:
<?php
/**
* PHPDom iterate through document and remove nodes without XPath
*/
/my totally random html
$html = '<p> Great <div> dont want this</div> </p><p> some more</p><div>more crap here</div>';
$doc = new DOMDocument();
$doc->recover = true;
$saved = libxml_use_internal_errors(true);
$doc->loadHTML($html);
libxml_use_internal_errors($saved);
$divs = iterator_to_array($doc->getElementsByTagName('div'));
foreach ($divs as $div) {
$div->parentNode->removeChild($div);
}
echo $doc->saveHTML();
loadHTML($html);
libxml\u使用\u内部错误($saved);
$divs=迭代器到数组($doc->getElementsByTagName('div');
foreach($div作为$div){
$div->parentNode->removeChild($div);
}
echo$doc->saveHTML();
删除第一个div的原因可能最简单的解释如下:
迭代所有子节点。此迭代首先将当前节点设置为第一个子节点()。然后处理该子项,完成后继续处理下一个子项(即)
但是如果现在从父节点中删除当前节点
$object->parentNode->removeChild($object);
迭代中的当前节点不再有任何下一个同级节点(因为它已从其父节点中删除)。因此,foreach迭代在删除第一个div元素后立即结束
有不同的方法来解决这个问题。使用纯PHP且不使用任何xpath,可以先将要删除的所有节点存储在一个数组中,然后删除它们。该功能在以下情况下非常方便:
$divs = iterator_to_array($doc->getElementsByTagName('div'));
foreach ($divs as $div) {
$div->parentNode->removeChild($div);
}
这四行代码确实替换了(不工作的)函数(!)的所有迭代和递归逻辑
您还可以通过在迭代当前元素(缓存当前元素)时使用内部已包含下一个元素的来修复函数。它不会失效,因为从父节点移除当前节点的那一刻,下一个节点已经被获取
大致用于更改以下行的代码:
foreach($object->childNodes as $child) {
iterate_children($child);
}
致:
但请注意,此代码仅用于演示目的。如果您将其复制并粘贴到示例中,它将崩溃,因为您的代码中存在一些其他问题,这些问题将随着这样的更改而变得严重
这段代码仍然具有实际上不需要的递归,因为您可以按文档顺序迭代节点。为此,我有一个域节点编辑器。该库中还有一个简单的DOMElementFilter。由于下一个兄弟姐妹的问题在这里是相同的,因此使用这两个兄弟姐妹还需要一个cachingierator:
$divs = new CachingIterator(new DOMElementFilter(new DOMNodeIterator($doc), 'div'), CachingIterator::TOSTRING_USE_KEY);
foreach ($divs as $div) {
$div->parentNode->removeChild($div);
}
这段代码与迭代器-to-array
示例非常相似。由于迭代器的装饰性,它通常使您能够创建更多可重用的代码
我希望这有助于您理解为什么会发生这种情况,并展示了一些处理方法
出于完整性的考虑,以下是具有更好错误处理和遍历逻辑的代码:
function iterate_children(DOMNode $node)
{
if ($node instanceof DOMElement and $node->tagName == "div") {
$parent = $node->parentNode;
$parent->removeChild($node);
return;
}
$children = $node->childNodes;
if (!$children) {
return;
}
$children = new IteratorIterator($children);
$children = new CachingIterator($children, CachingIterator::TOSTRING_USE_KEY);
foreach ($children as $child) {
iterate_children_old($child);
}
}
这里是不使用递归和数组的实现:
<?php
/**
* PHPDom iterate through document and remove nodes without XPath
*/
/my totally random html
$html = '<p> Great <div> dont want this</div> </p><p> some more</p><div>more crap here</div>';
$doc = new DOMDocument();
$doc->recover = true;
$saved = libxml_use_internal_errors(true);
$doc->loadHTML($html);
libxml_use_internal_errors($saved);
$divs = iterator_to_array($doc->getElementsByTagName('div'));
foreach ($divs as $div) {
$div->parentNode->removeChild($div);
}
echo $doc->saveHTML();
loadHTML($html);
libxml\u使用\u内部错误($saved);
$divs=迭代器到数组($doc->getElementsByTagName('div');
foreach($div作为$div){
$div->parentNode->removeChild($div);
}
echo$doc->saveHTML();
您为什么在此处使用引用?您在这里不处理变量别名,参数变量的值也没有任何更改?!好电话。当我使用那个参照物时,我有一些站不住脚的理由,但现在记不起来了。天色已晚,我绝望了……:)你为什么在这里使用参考文献?您在这里不处理变量别名,参数变量的值也没有任何更改?!好电话。当我使用那个参照物时,我有一些站不住脚的理由,但不要