5

So I've been at this for quite a while, and the best I got is wrapping the image in a link and with a span after the image tag:

<a href="">
  <img src="">
  <span></span>
</a>

But wat I want is:

<a href="">
  <span></span>
  <img src="">
</a>

I tried al kinds of variatons and positions of

$img->parentNode->appendChild($dom->createElement('span'), $img);

and the use of insertBefore() on all kinds of places in my code and I'm completely out of ideas since I'm fairly new to the php DOM stuff. My source:

foreach($dom->getElementsByTagName('img') as $img)
{
$fancyHref = $dom->createElement('a');

                        $clone = $fancyHref->cloneNode();
                        $img->parentNode->replaceChild($clone, $img);
                        $clone->appendChild($img);  
                        $img->parentNode->appendChild($dom->createElement('span'));
};

Update: To clarify my goal: I have an img tag in the html. After it goes through the php dom I want the img tag wrapped in an a tag with a span tag before the image tag:

Before

<img src="" />

After

<a href="">
   <span class=""></span>
   <img src="" />
</a>

My code at the moment for doing this (without the span)

foreach($dom->getElementsByTagName('img') as $img)
            {               
                $src = $img->getAttribute('src');
                $filename = substr(strrchr($src , '/') ,1); 
                $filename = preg_replace('/^[.]*/', '', $filename);
                $filename = explode('.', $filename); 
                $filename = $filename[0];

                if($this->imagesTitles[$this->currentLanguage][$filename] !== '')
                {
                    $img->setAttribute('title', $this->imagesTitles[$this->currentLanguage][$filename]);
                    $img->setAttribute('alt', $this->imagesTitles[$this->currentLanguage][$filename]);
                }
                else
                {
                    $img->removeAttribute('title');
                    $img->removeAttribute('alt');
                }

                $classes = explode(' ', $img->getAttribute('class'));
                if(!in_array('no-enlarge', $classes))
                {
                    $fancyHref = $dom->createElement('a');
                    $span = $dom->createElement('span');
                    $span->setAttribute('class', 'magnifier');
                    $fancyHref->setAttribute('class', 'enlarge');
                    $fancyHref->setAttribute('rel', 'enlarge');
                    $fancyHref->setAttribute('href', $img->getAttribute('src'));
                    if($img->getAttribute('title') !== '')
                    {
                        $fancyHref->setAttribute('title', $img->getAttribute('title'));
                        $fancyHref->setAttribute('alt', $img->getAttribute('title'));
                    }
                    $clone = $fancyHref->cloneNode();

                    $img->parentNode->replaceChild($clone, $img);   
                    $clone->appendChild($img);
                    $img->parentNode->insertBefore($span, $img);                        
                }

                $img->setAttribute('class', trim(str_replace('no-enlarge', '', $img->getAttribute('class'))));

                if($img->getAttribute('class') === '')
                {
                    $img->removeAttribute('class');
                }
            }
Rick de Graaf
  • 968
  • 1
  • 14
  • 35
  • Where are these functions from `parentNode` ...? – Mr.Web Aug 31 '13 at 12:29
  • To get things straight, you have an image already and you want to put span before it? – Itay Aug 31 '13 at 12:36
  • Yeas. I have an image tag in the HTML. What I want to do is wrap an a around it and put an span tag with class before it. I updated the question to explain what I want. – Rick de Graaf Sep 02 '13 at 10:31

2 Answers2

1

You can use the DOMNode->insertBefore() method (docs). It has the form $parentNode->insertBefore( $nodeToBeInserted, $nodeToInsertBefore ). Your code would be:

$img->parentNode->insertBefore( $dom->createElement('span'), $img );

DOMNode->appendChild() (docs) only has 1 argument (the inserted node), and this node will always be inserted after the last childNode.

Edit:

I've now tested my code, and if you would replace $img->parentNode->appendChild($dom->createElement('span')); with my line in your test case, it would end up with the correct format. You are however manipulating elements in a very confusing way. Besides that, if I test your updated code, I either end up with your desired format, or without a span element at all...

The element you want to replace is the image, because that is the only element that is originally in the document. Therefore, you should clone -that- element. While your current code eliminates the hierarchy error, you are copying all the changed code, instead of just the conflicting element and that is a waste of memory and time. When you copy the conflicting element, it is easy. You append the elements to your a in the order you want them to appear. When you append the image, append the clone instead. Do not manipulate $img. If you need to manipulate the image, you have to manipulate the clone instead. Then you just replace $img by the elements you manipulated ($fancyHref in your case).

$html = '<img src="">';
$dom = new DOMDocument();
$dom->loadHTML($html);

foreach($dom->getElementsByTagName('img') as $img) {
  $fancyHref = $dom->createElement('a');
  $clone = $img->cloneNode();
  $span = $dom->createElement( 'span' );
  #... do whatever you need to do to this span, the clone and the a element ...

  #... when you are done, you can simply append all elements you have been manipulating ...
  $fancyHref->appendChild( $span );
  $fancyHref->appendChild( $clone );

  $img->parentNode->replaceChild( $fancyHref, $img );
};

echo $dom->saveHTML();
Sumurai8
  • 20,333
  • 11
  • 66
  • 100
  • Tried that as well and the best result I get is that the image is put within the span tag. – Rick de Graaf Sep 02 '13 at 10:21
  • What doctype do you have? – Sumurai8 Sep 02 '13 at 11:13
  • Hmmm; that doesn't seem to make anything different. – Sumurai8 Sep 02 '13 at 16:27
  • I used your code (and thanks for the explanation) but still my span was generated around the image tag. I was using mb_substr($dom->saveXML($xpath->query('//body')->item(0)), 6, -7, "UTF-8") to output the code because that gets everything in the body tag (and that's wat I want). But after I tried saveHTML your code worked. Now I need to find a workaround for getting the body only but I'll think I'll find one. Thanks! – Rick de Graaf Sep 03 '13 at 07:43
  • For those interested, I fixed the code in my comment above with the answer found here: http://stackoverflow.com/a/16524589/317326 – Rick de Graaf Sep 03 '13 at 07:54
0

Ummm. I know this may not classify as an answer, but don't you already have it? I mean.. I tried your code:

$dom = new DOMDocument;
$dom->loadHTMLFile("data.html");

foreach($dom->getElementsByTagName('img') as $img){
    $src = $img->getAttribute('src');

    $filename = substr(strrchr($src , '/') ,1);
    $filename = preg_replace('/^[.]*/', '', $filename);
    $filename = explode('.', $filename);
    $filename = $filename[0];

    $classes = explode(' ', $img->getAttribute('class'));

    if(!in_array('no-enlarge', $classes))
    {
        $fancyHref = $dom->createElement('a');
        $span = $dom->createElement('span');
        $span->setAttribute('class', 'magnifier');
        $fancyHref->setAttribute('class', 'enlarge');
        $fancyHref->setAttribute('rel', 'enlarge');
        $fancyHref->setAttribute('href', $img->getAttribute('src'));
        if($img->getAttribute('title') !== '')
        {
            $fancyHref->setAttribute('title', $img->getAttribute('title'));
            $fancyHref->setAttribute('alt', $img->getAttribute('title'));
        }
        $clone = $fancyHref->cloneNode();

        $img->parentNode->replaceChild($clone, $img);
        $clone->appendChild($img);
        $img->parentNode->insertBefore($span, $img);
    }

    $img->setAttribute('class', trim(str_replace('no-enlarge', '', $img->getAttribute('class'))));

    if($img->getAttribute('class') === ''){
        $img->removeAttribute('class');
    }
}

echo "<pre>" . htmlentities($dom->saveHTML()) . "</pre>";

With this (data.html) as source data:

<!doctype html>
<html>
    <head>
    </head>
    <body>
        <img src="http://lorempixel.com/g/400/200/" alt="alts" title="tits">
    </body>
</html>

And the result is this:

<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <a class="enlarge" rel="enlarge" href="http://lorempixel.com/g/400/200/" title="tits" alt="tits">
            <span class="magnifier">
            </span>
            <img src="http://lorempixel.com/g/400/200/" alt="alts" title="tits"></a>
    </body>
</html>

So.. Isn't that what you wanted? :D

Smuuf
  • 6,339
  • 3
  • 23
  • 35