- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有一个可怕的算法,“删除一个节点”,将其内部内容移动到它的父节点(见下文)......但是我认为可以开发一个更好的算法,使用DOMDocumentFragment (并且不使用 saveXML/loadXML)。
以下算法的灵感来自 renameNode() .
/**
* Move the content of the $from node to its parent node.
* Conditions: parent not a document root, $from not a text node.
* @param DOMElement $from to be removed, preserving its contents.
* @return true if changed, false if not.
*/
function moveInner($from) {
$to = $from->parentNode;
if ($from->nodeType==1 && $to->parentNode->nodeType==1) {
// Scans $from, and record information:
$lst = array(); // to avoid "scan bugs" of DomNodeList iterator
foreach ($to->childNodes as $e)
$lst[] = array($e);
for($i=0; $i<count($lst); $i++)
if ($lst[$i][0]->nodeType==1 && $from->isSameNode($lst[$i][0])) {
$lst[$i][1] = array();
foreach ($lst[$i][0]->childNodes as $e)
$lst[$i][1][] = $e;
}
// Build $newTo (rebuilds the parent node):
$newTo = $from->ownerDocument->createElement($to->nodeName);
foreach ($to->attributes as $a) {
$newTo->setAttribute($a->nodeName, $a->nodeValue);
}
foreach ($lst as $r) {
if (count($r)==1)
$newTo->appendChild($r[0]);
else foreach ($r[1] as $e)
$newTo->appendChild($e);
}
// Replaces it:
$to->parentNode->replaceChild($newTo, $to);
return true;
} else
return false;
}
输入
<html id="root">
<p id="p1"><i>Title</i></p>
<p id="p2"><b id="b1">Rosangela<sup>1</sup>, Maria<sup>2</sup></b>,
<b>Eduardo<sup>4</sup></b>
</p>
</html>
moveInner($dom->getElementById('p1'))
的输出
... <p id="p1">Title</p> ...
moveInner($dom->getElementById('b1'))
的输出
... <p id="p2">Rosangela<sup>1</sup>, Maria<sup>2</sup>,
<b>Eduardo<sup>4</sup></b>
</p> ...
moveInner($dom->getElementById('root'))
或 moveInner($dom->getElementById('p1'))
没有变化首次使用后。
PS:就像一个“TRIM TAG”功能。
最佳答案
当您在同一个文档中移动时,这实际上并没有那么麻烦。您单独发布的代码已经有很多地方可以单独优化,例如将 childNodes
NodeList
转换为数组只需使用 iterator_to_array
:
$children = iterator_to_array($from->childNodes);
另外你应该使用更多的说话变量名,有更长的名字没有问题。它只是使代码更具可读性,并留出空间以更快地查看更重要的内容:
/**
* Move the content of the $from node to its parent node.
*
* @param DOMElement $from to be removed, preserving its contents.
* @return DOMElement the element removed (w/o it's former children)
* @throws InvalidArgumentException in case there is no parent element
*/
function moveInner(DOMElement $from)
{
if (!$from->parentNode instanceof DOMElement) {
throw new InvalidArgumentException(
'DOMElement does not have a parent DOMElement node.'
);
}
/** @var DOMNode[] $children */
$children = iterator_to_array($from->childNodes);
foreach ($children as $child) {
$from->parentNode->insertBefore($child, $from);
}
return $from->parentNode->removeChild($from);
}
它只是工作。如果您将 相同 元素插入 DOMDocument 中的另一个位置,该元素将被移动,而不是被复制。
如果你想复制(为了保留子节点,而不是移动它),你可以使用子节点作为原型(prototype)并克隆它们。由于此函数返回被删除的元素,因此它包含副本。
首先是没有克隆的例子,只是上面的函数:
$removed = moveInner($doc->getElementById('b1'));
echo $doc->saveHTML(), "\nRemoved: ", $doc->saveHTML($removed);
输出:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html id="root"><body><p id="p1"><i>Title <b>2</b></i></p>
<p id="p2">Rosangela<sup>1</sup>, Maria<sup>2</sup>,
<b>Eduardo<sup>4</sup></b>
</p>
</body></html>
Removed: <b id="b1"></b>
然后第二个修改函数,变化只是在下面的行中添加clone
:
$from->parentNode->insertBefore(clone $child, $from);
#####
输出:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html id="root"><body><p id="p1"><i>Title <b>2</b></i></p>
<p id="p2">Rosangela<sup>1</sup>, Maria<sup>2</sup>,
<b>Eduardo<sup>4</sup></b>
</p>
</body></html>
Removed: <b id="b1">Rosangela<sup>1</sup>, Maria<sup>2</sup></b>
希望本文对您有所帮助并满足您的需求。您那里确实有很多代码,可能有点被不同的替换节点场景误导了。同样在那种情况下,我正在修补一些不同的错误代码,这些错误代码并不总是更改为好代码的最佳基础。
顺便说一句。让我想起了我今天刚刚回答的克隆也很有帮助的问题:
关于php - 如何使用 DOMDocumentFragment 移动内部内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18849693/
我有一个可怕的算法,“删除一个节点”,将其内部内容移动到它的父节点(见下文)......但是我认为可以开发一个更好的算法,使用DOMDocumentFragment (并且不使用 saveXML/lo
请参阅“有效” 和“无效” 部分:是我的代码错误还是 DOMDocument-PHP 实现的错误? 如果您不熟悉 XSLT 和 registerPHPFunctions 请参阅 this link f
我需要将一些任意 HTML 加载到现有的 DOMDocument 树中。以前的答案建议使用 DOMDocumentFragment及其 appendXML处理这个问题的方法。 作为@Owlvark在评
经过一番尝试和错误后,我注意到我的模板引擎在包含 的模板文件上失败。标签。这显然是一个大问题,但我似乎无法弄清楚它失败的原因。 它失败的方式也很奇特。随着标签被注释掉,页面加载正常,但是带有 标签取
我是一名优秀的程序员,十分优秀!