gpt4 book ai didi

php - 如何在 PHP 中删除重复的、嵌套的 DOM 元素?

转载 作者:行者123 更新时间:2023-11-28 04:24:38 25 4
gpt4 key购买 nike

假设您有一个带有嵌套标签的 DOM 树,我想通过删除重复项来清理 DOM 对象。但是,这只适用于标签只有一个子标签的情况同一类型。例如,

修复 <div><div>1</div></div>而不是 <div><div>1</div><div>2</div></div> .

我正在尝试弄清楚如何使用 PHP's DOM extension 来做到这一点.下面是起始代码,我正在寻求帮助来确定所需的逻辑。

<?php

libxml_use_internal_errors(TRUE);

$html = '<div><div><div><p>Some text here</p></div></div></div>';

$dom = new DOMDocument;
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadHTML($html);

function dom_remove_duplicate_nodes($node)
{
var_dump($node);

if($node->hasChildNodes())
{
for($i = 0; $i < $node->childNodes->length; $i++)
{
$child = $node->childNodes->item($i);

dom_remove_duplicate_nodes($child);
}
}
else
{
// Process here?
}
}

dom_remove_duplicate_nodes($dom);

我收集了一些帮助函数,这些函数可以使像 JavaScript 一样更容易地处理 DOM 节点。

function DOM_delete_node($node)
{
DOM_delete_children($node);
return $node->parentNode->removeChild($node);
}

function DOM_delete_children($node)
{
while (isset($node->firstChild))
{
DOM_delete_children($node->firstChild);
$node->removeChild($node->firstChild);
}
}

function DOM_dump_child_nodes($node)
{
$output = '';
$owner_document = $node->ownerDocument;

foreach ($node->childNodes as $el)
{
$output .= $owner_document->saveHTML($el);
}
return $output;
}

function DOM_dump_node($node)
{
if($node->ownerDocument)
{
return $node->ownerDocument->saveHTML($node);
}
}

最佳答案

您可以使用 DOMDocumentDOMXPath 轻松完成此操作. XPath 在您的情况下尤其有用,因为您可以轻松划分逻辑以选择要删除的元素以及删除元素的方式。

首先,规范化输入。我不完全清楚你对空空格的意思,我认为它可能是空文本节点(可能已被删除,因为 preserveWhiteSpaceFALSE 但我不确定)或者它们是否规范化空白为空。我选择了第一个(如果有必要的话),以防它是另一个变体,我留下了评论使用什么来代替:

$xp = new DOMXPath($dom);

//remove empty textnodes - if necessary at all
// (in case remove WS: [normalize-space()=""])
foreach($xp->query('//text()[""]') as $i => $tn)
{
$tn->parentNode->removeChild($tn);
}

在此 textnode 规范化之后,您应该不会遇到您在此处评论中提到的问题。

下一部分是找到所有与其父元素同名并且是唯一子元素的元素。这又可以用xpath来表示。如果找到这样的元素,则将其所有子元素移动到父元素,然后该元素也将被删除:

// all child elements with same name as parent element and being
// the only child element.
$r = $xp->query('body//*/child::*[name(.)=name(..) and count(../child::*)=1]');
foreach($r as $i => $dupe)
{
while($dupe->childNodes->length)
{
$child = $dupe->firstChild;
$dupe->removeChild($child);
$dupe->parentNode->appendChild($child);
}
$dupe->parentNode->removeChild($dupe);
}

Full demo .

如您在演示中所见,这独立于文本节点和注释。如果你不想要那个,例如在实际文本中,计算子项的表达式需要覆盖所有节点类型。但我不知道这是否是您的确切需求。如果是,则计算所有节点类型的子节点数:

body//*/child::*[name(.)=name(..) and count(../child::node())=1]

如果您没有预先规范化空文本节点(删除空文本节点),那么这就太严格了。选择你需要的工具集,我认为规范化加上这个严格的规则可能是最好的选择。

关于php - 如何在 PHP 中删除重复的、嵌套的 DOM 元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7972199/

25 4 0
文章推荐: javascript - 在 JavaScript 中设置底部 CSS 属性
文章推荐: javascript - 错误消息在简单的 javascript 表单验证中不起作用
文章推荐: c++ - 我的 findContours() 函数在具有不同 dpi 的图像上表现异常
文章推荐: javascript - 在 <input> 中动态添加
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com