我有以下html代码:
$pageHTML = '<html>
<head></head>
<body>
<div class="some class">
<header>Header</header>
<section>Section</section>
<footer>Footer</footer>
</div>
</body>
</html>';
我需要删除<div>
的外部标签,并将其所有内部HTML都保留在<body>
如果我尝试
$dom = new DOMDocument;
libxml_use_internal_errors(true);
$dom->loadHTML($pageHTML);
libxml_use_internal_errors(false);
$bodyDivs = [];
foreach($dom->getElementsByTagName('body')[0]->childNodes as $bodyChild) {
if($bodyChild->nodeName == 'div') {
$bodyDivs[] = $bodyChild;
}
}
if(count($bodyDivs) == 1) {
foreach($bodyDivs[0]->childNodes as $divChild) {
$dom->getElementsByTagName('body')[0]->appendChild($divChild);
}
$dom->getElementsByTagName('body')[0]->removeChild($bodyDivs[0]);
}
div已被删除,但在删除之前未将其子级附加到<body>
如果我尝试反向循环
$k = count($bodyDivs[0]->childNodes);
for($n = $k-1; $n >= 0; $n--) {
$dom->getElementsByTagName('body')[0]->appendChild($bodyDivs[0]->childNodes[$n]);
}
$dom->getElementsByTagName('body')[0]->removeChild($bodyDivs[0]);
孩子被添加到身体中,但顺序相反
我明白了
<body>
<footer>Footer</footer>
<section>Section</section>
<header>Header</header>
</body>
但我需要
<body>
<header>Header</header>
<section>Section</section>
<footer>Footer</footer>
</body>
如何解决问题?
答案 0 :(得分:1)
您的原始代码非常接近,只缺少一个关键点。
原始代码
foreach
尝试<body>
个节点列表,同时也从同一列表中删除节点(在您的情况下,将它们移动到<?php
$doc = new DOMDocument;
$doc->loadXML('<example><a/><b/><c/><d/><e/></example>');
$parent = $doc->documentElement;
foreach ($parent->childNodes as $child) {
$parent->removeChild($child);
}
echo $doc->saveXML();
),并没有达到预期的效果。
简化的完整示例,用于演示:
<?xml version="1.0"?>
<example><b/><c/><d/><e/></example>
这将输出以下内容:
<?php
$doc = new DOMDocument;
$doc->loadXML('<example><a/><b/><c/><d/><e/></example>');
$parent = $doc->documentElement;
while ($parent->childNodes->length > 0) {
$child = $parent->childNodes->item(0);
$parent->removeChild($child);
}
echo $doc->saveXML();
完全明智,对吧?不要害怕,我们可以做得更好。
该怎么办?
行为确实符合预期的一种常见方法是遍历列表,直到列表为空。
foreach
应用于您的代码
以上所有内容都表示您的原始foreach($bodyDivs[0]->childNodes as $divChild) {
$dom->getElementsByTagName('body')[0]->appendChild($divChild);
}
:
while ($bodyDivs[0]->childNodes->length > 0) {
$divChild = $bodyDivs[0]->childNodes->item(0);
$dom->getElementsByTagName('body')->item(0)->appendChild($divChild);
}
可以用while循环替换。
->item(0)
在旁边:我使用上面的<int:logging-channel-adapter>
表示法,因为这是比较传统的方法。
答案 1 :(得分:0)
好的,我已经找到了自己的解决方案,但也许有人会发表更优雅的话:
if(count($bodyDivs) == 1) {
$count = count($bodyDivs[0]->childNodes);
$arr = [];
for($n = $count-1; $n >= 0; $n--) {
$arr[] = $bodyDivs[0]->childNodes[$n];
}
for($n = $count-1; $n >= 0; $n--) {
$dom->getElementsByTagName('body')[0]->appendChild($arr[$n]);
}
$dom->getElementsByTagName('body')[0]->removeChild($bodyDivs[0]);
}
echo str_replace("\n\r", "", $dom->saveHTML((new \DOMXPath($dom))->query('/')->item(0)));