0

I would like to replace <includes module="styles" /> with the $styles string at the position where it is. Unfortunately it appends it in the body and not in the head. Anyway, maybe there is another way to realize this issue?

$xml = <<<EOD
<!DOCTYPE html>
<html>
<head>
    <title></title>
    <includes module="styles" />
</head>
<body>
    <includes module="m1" />
    <includes module="m2" />
</body>
</html>
EOD;


$styles = <<<EOD
<styles>
    .m1{
        font-size: 12px;
        font-family: Helvetica, Arial, sans-serif;
        color: blue;
    }
</styles>
EOD;


$dom = new DOMDocument();
$dom->loadXML($xml);

$elements = $dom->getElementsByTagName('includes');
for ($i = $elements->length-1; $i >= 0; $i--) { 
    $element = $elements->item($i);

    $newNode = $dom->createDocumentFragment();
    $mod = $element->getAttribute('module');
    if($mod==='styles'): $newNode->appendXML($styles); endif;
    $element->parentNode->replaceChild($newNode, $element);
}

print $dom->saveXml($dom->documentElement);

cheers

domizai
  • 343
  • 1
  • 5
  • 13
  • Use bracket syntax instead of alternative syntax for your if, also indent the code there. This should make it much more visible for you where you did a little mistake. 99.9% of the code looks good. – hakre May 22 '14 at 21:52

2 Answers2

0

You need to put the $element->parentNode->replaceChild($newNode, $element); inside your IF clause.
I also recommend to use foreach and bracket (makes it more readable)

foreach ($dom->getElementsByTagName('includes') as $element) { 
   $mod = $element->getAttribute('module');
   if($mod === 'styles') {
      $newNode = $dom->createDocumentFragment();
      $newNode->appendXML($styles);
      $element->parentNode->replaceChild($newNode, $element);
   }
}
Javad
  • 4,339
  • 3
  • 21
  • 36
  • and using foreach will only consider the first found 'includes' element. You have to iterate backwards somehow... – domizai May 22 '14 at 22:37
  • foreach works if you copy the node list into an array `$elements = iterator_to_array($dom->getElementsByTagName('includes'));` or use xpath. You might want to add a removeChild for the elements you do not replace. – ThW May 23 '14 at 07:00
  • This gives me a length of 0.. ? Another thing is, when i only use saveXML() without manipulation it automatically moves any custom tag in the head, like 'includes' to the body. When i use loadHTML() i even get a warning: 'Tag includes invalid in Entity' – domizai May 23 '14 at 08:52
  • 1
    @domizai Test result http://sandbox.onlinephpfunctions.com/code/bbd1355314e1c26dc5fefaf21635e3f260c9647f – Javad May 23 '14 at 14:15
  • The reason that `loadHTML` did not work was it loads it base on HTML DOM and the `` tag is not a HTML DOM element – Javad May 23 '14 at 14:18
0

I found the bug, and it's pretty embarrassing! I misspelled <styles>. its supposed to be <style>! Obviously it automatically moves custom tags into the body.

@Javad That's funny. Because the php tester leaves the wrong styles tag in the head, but not on my xampp. Maybe because it has something to do with the php version?

domizai
  • 343
  • 1
  • 5
  • 13