1

I am trying to replace the HTML5 elements with a <div tag for older browsers.

Code I am using is as follows. I simplified for easy understanding:

    <article class="article">article - Lorem ipsum dolor sit amet</article>

    <pre>
        <article class="article-pre">article - Lorem ipsum dolor sit amet</article>
        <summary class="summary-pre">summary - Lorem ipsum dolor sit amet</summary>
    </pre>

    <code>
        <article class="article-pre">Lorem ipsum dolor sit amet</article>
        <summary class="summary-pre">Lorem ipsum dolor sit amet</summary>
    </code>

I tried doing some experiments but failed. I used the code as follows:

$dom = new DOMDocument;
$dom->loadHTML($content);
$xp = new DOMXPath($dom);
$nodes = $xp->query('//text()[not(ancestor::pre) and contains(.,' . $element . ')]');
foreach($nodes as $node) {
    $node->nodeValue = str_replace($element, $replace, $node->nodeValue);
}
echo $dom->saveXML($dom->documentElement);
  1. I want this thing to work on JavaScript disabled browsers that do not support HTML5 elements, hence using any JavaScript is not an option.

  2. If there is any other better way to do this using php then please suggest.

Alan Moore
  • 73,866
  • 12
  • 100
  • 156
Vikram Rao
  • 1,068
  • 4
  • 24
  • 62

1 Answers1

1

You've probably oversimplified the code, as it stands it will only replace the opening tag, which will at least cause the browser to hop into quirks mode.

Anyways, this is definitely possible using DOM (though it will throw warnings because of unsupported HTML5 elements, see https://stackoverflow.com/a/6090728/1392379), however your XPath query is wrong, you cannot simply pass an array into it. And even if your query would work, it would only select all the individual text nodes, so there wouldn't be anything to replace.

Changing the name of a node is not possible directly, you'll have to replace the node with a new one. Here's an example that uses a static XPath query. It copies the selected nodes attributes and child nodes into a new div node, and then replaces the original node with the new one:

$dom = new DOMDocument;
$dom->loadHTML($content);

$xp = new DOMXPath($dom);
$nodes = $xp->query('//*[self::article|self::summary|self::aside][not(ancestor::pre) and not(ancestor::code)]');

foreach($nodes as $node)
{
    $newNode = $dom->createElement('div');
    while($node->childNodes->length)
    {
        $childNode = $node->childNodes->item(0);
        $newNode->appendChild($dom->importNode($childNode, true));
    }
    while($node->attributes->length)
    {
        $attributeNode = $node->attributes->item(0);
        $newNode->setAttributeNode($dom->importNode($attributeNode));
    }
    $node->parentNode->replaceChild($newNode, $node);
}

echo $dom->saveXML($dom->documentElement);

Update Fixed the code example by using while instead of a foreach on childNodes/attributes. The latter will cause a hickup when not cloning the node that is going to be appended and consequently removed from the node list being iterated.

Using a for loop should work fine too:

for($i = 0; $i < $node->childNodes->length; $i ++)
{
    $childNode = $node->childNodes->item($i);
    $newNode->appendChild($dom->importNode($childNode, true));
}
for($i = 0; $i < $node->attributes->length; $i ++)
{
    $attributeNode = $node->attributes->item($i);
    $newNode->setAttributeNode($dom->importNode($attributeNode));
}

as well as the cloning mentioned initially:

foreach($node->childNodes as $childNode)
{
    $newNode->appendChild($dom->importNode($childNode->cloneNode(true), true));
}
foreach($node->attributes as $attributeNode)
{
    $newNode->setAttributeNode($dom->importNode($attributeNode->cloneNode()));
}
$node->parentNode->replaceChild($newNode, $node);
Community
  • 1
  • 1
ndm
  • 59,784
  • 9
  • 71
  • 110
  • In principle it works fine but there is a challenge. For example : `
    1
    2
    3
    4
    5
    6
    `
    – Vikram Rao Aug 12 '13 at 19:44
  • It only shows the first div `
    1
    ` all the other following divs are missing. Why is that?
    – Vikram Rao Aug 12 '13 at 19:45
  • Sorry, my fault. This is because appending a node removes the node from the node list and also decreases the lists length, which causes a hickup when using such a `foreach` construct for iterating over the child/attribute nodes. This can be avoided by for example cloning the node, or by using a `while` or `for` loop instead. I've updated my example. – ndm Aug 12 '13 at 20:26