I have a horrible algorithm, to "remove a node", moving its inner content to its parent node (see below)... But I think is possible to develop a better algorithm, using DOMDocumentFragment (and not using saveXML/loadXML).
The algorithm below was inspired by 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;
}
Example
INPUT
<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>
OUTPUT of moveInner($dom->getElementById('p1'))
... <p id="p1">Title</p> ...
OUTPUT of moveInner($dom->getElementById('b1'))
... <p id="p2">Rosangela<sup>1</sup>, Maria<sup>2</sup>,
<b>Eduardo<sup>4</sup></b>
</p> ...
There are no changes in moveInner($dom->getElementById('root'))
, or moveInner($dom->getElementById('p1'))
after first use.
PS: is like a "TRIM TAG" function.