7

How would you add a class named newClass to an opening tag like <a class='abc'> or <p style=display:block> using php?

jantimon
  • 36,840
  • 23
  • 122
  • 185
  • 1
    For an existing file that you're parsing with PHP, or a file that you're generating using PHP? – deceze May 19 '11 at 09:01
  • Its generated and only an opening tag. – jantimon May 19 '11 at 09:19
  • So, you're *not* parsing an existing file? Then the usual way is to just write `class="newClass"` where it's supposed to appear... Can you perhaps clarify your situation? – deceze May 19 '11 at 09:22
  • My function generates a diff between two HTML codes. Modified strings are wrapped by a new span but modified existing elements should get an additional class. – jantimon May 19 '11 at 09:23
  • @Ghommey I would really recommend to use DOM* functionality for this. If you can give a more detailed example, we'll surely can help you better. – Yoshi May 19 '11 at 09:26
  • The reason for my function is similar to this so thread: http://stackoverflow.com/questions/31722/anyone-have-a-diff-algorithm-for-rendered-html – jantimon May 19 '11 at 09:29

2 Answers2

9

Regexp example:

<?php
function addClass($htmlString = '', $newClass) {
    $pattern = '/class="([^"]*)"/';

    // class attribute set
    if (preg_match($pattern, $htmlString, $matches)) {
        $definedClasses = explode(' ', $matches[1]);
        if (!in_array($newClass, $definedClasses)) {
            $definedClasses[] = $newClass;
            $htmlString = str_replace($matches[0], sprintf('class="%s"', implode(' ', $definedClasses)), $htmlString);
        }
    }

    // class attribute not set
    else {
        $htmlString = preg_replace('/(\<.+\s)/', sprintf('$1class="%s" ', $newClass), $htmlString);
    }

    return $htmlString;
}

echo addClass('<a class="abc">', 'newClass');
echo addClass('<p style=display:block>', 'newClass');

using http://php.net/manual/en/book.dom.php example

<?php
function addClass($node = null, $className) {
    $result = false;

    if (is_string($node)) {
        $dom = DOMDocument::loadXml($node);
        if ($dom instanceof DOMDocument) {
            $definedClasses = explode(' ', $dom->documentElement->getAttribute('class'));
            if (!in_array($className, $definedClasses)) {
                $dom->documentElement->setAttribute(
                    'class', $dom->documentElement->getAttribute('class') . ' ' . $className
                );
            }

            $result = $dom->saveXml($dom->documentElement, true);
        }
    }
    elseif ($node instanceof DOMElement) {
        // this code repetition, could of course be avoided using some more sophisticated structures 
        $definedClasses = explode(' ', $node->getAttribute('class'));
        if (!in_array($className, $definedClasses)) {
            $node->setAttribute('class', $node->getAttribute('class') . ' ' . $className);
        }

        $result = $node;
    }

    return $result;
}

// using a string as input
echo addClass('<a class="abc"></a>', 'newClass');

// using a DOMElement as input
$dom = DOMDocument::loadHtml('<div><a id="something"></a></div>');
$xpath = new DOMXPath($dom);

$node = $xpath->query('//*[@id="something"]')->item(0);
if ($node instanceof DOMElement) {
    addClass($node, 'newClass');
    echo $dom->saveXml($node, true);
}

I'm purposely not using loadHTML (inside the function) to prevent having to dive down into the autogenerated html structure to find the actual given $htmlString. This of course implies that $htmlString has to be well-formed.

Yoshi
  • 54,081
  • 14
  • 89
  • 103
2

Html class from Nette Framework does a perfect work for generating HTML tags in PHP.

Ondřej Mirtes
  • 5,054
  • 25
  • 36