5

I am trying to insert nodes in my html string. My goal is to insert an element before each h2 tag.

For that, I am using:

$htmlString = "<h2>some html</h2>";

$DOM = new DOMDocument();
$DOM->loadHTML($htmlString);

$itemTitles = $DOM->getElementsByTagName('h2');

for($i = 0; $i < $itemTitles->length; $i ++)
{
    $helpNavigatorContents[] = $itemTitles->item($i)->nodeValue;
    $textBefore = new DOMNode(
        '<a name="'.$itemTitles->item($i)->nodeValue.'"></a>'
    );
    $itemTitles->item($i)->parentNode->insertBefore(
        $textBefore, 
        $itemTitles->item($i)
    );
}

$htmlString = $DOM->saveHTML($DOM);

And here I have a problem with the $textBefore. When I declare the $textBefore as a DOMText, I can insert the text before the node but when I try this with DOMNode, then I am getting the following error (Demo):

Warning: DOMNode::insertBefore(): Couldn't fetch DOMNode

hakre
  • 193,403
  • 52
  • 435
  • 836
Milos Cuculovic
  • 19,631
  • 51
  • 159
  • 265

1 Answers1

9

The code doesn't make any sense. DOMNode does not have a constructor. It is not supposed to be created at all. You are supposed to create specific node types through DOMDocument to have them associated with the Document.

Assuming you want to prepend all the H2 element with an anchor, this is how to do it:

libxml_use_internal_errors(true);
$DOM = new DOMDocument();
$DOM->loadHTML($htmlString);
$DOM->preserveWhiteSpace = false;

foreach ($DOM->getElementsByTagName('h2') as $h2) {
    $a = $DOM->createElement('a');
    $a->setAttribute('name', $h2->nodeValue);
    $h2->parentNode->insertBefore($a, $h2);
}
$DOM->formatOutput = true;
echo $DOM->saveHTML();

Demo http://codepad.org/N0dPcLwT

To wrap the H2 elements into the A element, simply do the same and add

$a->appendChild($h2);

Demo http://codepad.org/w7Hi0Bmz

Gordon
  • 312,688
  • 75
  • 539
  • 559
  • Thank you very much @Gordon, I will try this and as soon I finish, I will let you know if I have some other trubles with. – Milos Cuculovic Sep 28 '12 at 14:28
  • It works as a charm @Gordon, the only think I would like to ask you: a new html body is inserted when adding those tags: – Milos Cuculovic Sep 28 '12 at 14:41
  • @Milos yes, when you use `loadHTML` it will try to fix any broken html and adds a minimal HTML skeleton. This cannot be turned off from PHP although it is possible in libxml. If you are on PHP > 5.3.6 you can use `$DOM->loadHTML($someNode)` to output the OuterHTML of that node. See http://stackoverflow.com/questions/5404941/php-domdocument-outerhtml-for-element/5404962#5404962 – Gordon Sep 28 '12 at 14:44
  • thanks again for your reply. I am using php 5.3.10-1ubuntu3.4 with Suhosin-Patch. When I am saving the html I am using $DOM->saveHTML($DOM); – Milos Cuculovic Sep 28 '12 at 14:53
  • @Milos well, like I said, passing a node gives the *OuterHTML*. If you dont want the entire Document, pass a subtree of the document. – Gordon Sep 28 '12 at 14:55
  • I am afraid I am not able to pass a subtree of the document. Can you give me an example please. Thanks a lot. – Milos Cuculovic Sep 28 '12 at 14:58
  • @Milos well, pass in `$DOM->documentElement`. That's the HTML element. Or `$DOM->getElementsByTagName('body')->item(0)` for the body element. You get the idea. – Gordon Sep 28 '12 at 15:00
  • oh yes, right. By passing $DOM->documentElement, now i have added, it's better than before. – Milos Cuculovic Sep 28 '12 at 15:03
  • @Milos if you want the innerHTML instead, see http://stackoverflow.com/questions/2087103/innerhtml-in-phps-domdocument – Gordon Sep 28 '12 at 15:04