PHPRO.ORG

This class simplifies the highlighting HTML code. There are many libraries which can do better, and use thousands of lines of code to do it. This class filled a simple need I had, and so, is less fully featured.

The class makes using PHP's DOM extension as a container for the HTML, and is then traversed to create a string of highlighted HTML code. All improvements welcomed.


<?php

/**
 *
 * @TODO Fix newline wrapping on divs and <p> tags
 *
 */

class htmlHighlighter extends domDocument{

    public 
$tag_color '#0000ff';    // tag name color
    
public $atr_color '#cc8400';    // attribute color
    
public $val_color '#ff0000';    // attribute value color
    
public $txt_color '#007700';    // text value color
    
public $com_color '#c0c0c0';    // comment value color

    
public $xml;
    
/**
     * Self closing tags do not require end tags
     */
    
public $self_closing_tags = ['area''base''br''col''command''embed''hr''img''input''keygen''link''meta''param''source''track''wbr'];

    
/**
     *
     * Constructor, duh
     *
     * @access    public
     * @param    string    $html
     *
     */
    
public function __construct$html )
    {
        
parent::__construct();
        
// add <base> tags to force a known root node
        
$html "<base>$html</base>";

        
$dom = new DOMDocument(); 
        
// need to suppress errors for badly formed HTML
        // LIBXML_HTML_NOIMPLIED turns off the automatic adding of implied html/body elements
        // LIBXML_HTML_NODEFDTD prevents a default doctype being added when one is not found.
        
@$dom->loadHTML$htmlLIBXML_HTML_NOIMPLIED LIBXML_HTML_NODEFDTD );
        
$xp = new DOMXPath($dom); 

        
// select the root node
        
$list $xp->query('/base/*'); 
        
$this->xml $this->processTree$list->item(0) ); 
    }

    
/**
     *
     * processes a node
     *
     * @access    public
     * @param    domNode    $root
     * @return    string
     *
     */
    
public function processTree$root 
    {
        
// if there is no child nodes
        
if ( $root->hasChildNodes() === false 
        {
            
// text nodes can't have child nodes so, no point in looking for one
            
if( $root->nodeName != '#text' )
            {
                
// is this a comment?
                
if( $root->nodeName == '#comment' )
                {
                    
$xml '<span style=color:'.$this->com_color.';">&lt;!--&nbsp;'.nl2brhtmlentities$root->nodeValue) ).'.&nbsp;--&gt;<br>';
                }
                else
                {    
                    
// opening tag for element
                    
$xml '<span style="color:'.$this->tag_color.';">&lt;'$root->nodeName.'</span>';

                    
// check for attributes
                    
if( $root->hasAttributes() !== false )
                    {
                        
$attributes '';
                        foreach (
$root->attributes as $attr)
                        {
                            
$attributes .= '&nbsp;<span style="color:'.$this->atr_color.';">'.$attr->nodeName.'</span>=<span style="color:'.$this->val_color.';">"'.$attr->nodeValue.'"</span>';
                        }
                        
$xml .= $attributes;    
                    }
        
                    
// closing greater-than to close the opening tag
                    
$xml .= '<span style="color:'.$this->tag_color.';">&gt;</span>';
    
                    
// is there any text in this tag?
                    
$xml .= htmlentities$root->nodeValue );

                    
// closing tag, only if required
                    
if( !in_array$root->nodeName$this->self_closing_tags ) )
                    {
                        
$xml .= '<span style="color:'.$this->tag_color.';">&lt;/'$root->nodeName  .'&gt;</span>';
                    }
                    
$xml .= '<br>';
                }
            }
            else
            {
                
// if this is a childless node, just add the value
                
$xml '<span style="color:'.$this->txt_color.';">'.htmlentities$root->nodeValue ).'</span>';
            }
        } 
        else
        {
            if( 
$root->nodeName != '#text' )
            {
                
// else, this is a non-text node, so get its node name as start tag... 
                
$xml '<span style="color:'.$this->tag_color.';">&lt;' $root->nodeName '</span>';
                
// ... followed by its contents... 
                
if( $root->hasAttributes() !== false )
                {
                    
$attributes '';
                    foreach ( 
$root->attributes as $attr )
                    {
                        
$attributes .= '&nbsp;<span style="color:'.$this->atr_color.';">'.$attr->nodeName.'</span>=<span style="color:'.$this->val_color.';">"'.$attr->nodeValue.'"</span>';
                    }
                    
$xml .= $attributes;    
                }    
                
// close the nodeName opening tag
                
$xml .= '<span style="color:'.$this->tag_color.';">&gt;</span>';

                
// TODO. Should only have new line if there is no child nodes
                
$xml .= '<br>';
                
// $xml .= $root->nodeValue.'<br>';
                
foreach( $root->childNodes as $node 
                {
                    
$xml .= $this->processTree$node ); 
                } 
                
// ... followed by its nodename as end tag 
                
$xml .= '<span style="color:'.$this->tag_color.';">&lt;/' $root->nodeName .'<span style="color:'.$this->tag_color.';">&gt;</span><br>';
            }
        }  
// end else
        
return $xml
    }  
// end func

    /**
     *
     * Returns the highlighted code 
     *
     * @access    public
     * @return    string
     *
     */
    
public function __toString()
    {
        return 
$this->xml;
    }

// end of class

Usage


<?php

$form 
'
<div>
<!-- comment here -->
<body>
<p>this @ is & not a love song</p>
<div>Div stuff here</div>
<div class="form_container">
<p>Broken tag
<!-- 
Multi line
comment here 
-->
<form method="post" action="process.php">
<input type="text" name="foo" value="foo">
<input type="submit" value="Lets go">
</form>
</div>
</body>
</div>
'
;

$hh = new htmlHighlighter$form );
echo 
$hh;
?>

Example

<div>
<!--  comment here . -->
<body>
<p>
this @ is & not a love song</p>
<div>
Div stuff here</div>
<div class="form_container">
<p>
Broken tag <!-- 
Multil line
comment here
. -->
</p>
<form method="post" action="process.php">
<input type="text" name="foo" value="foo">
<input type="submit" value="Lets go">
</form>
</div>
</body>
</div>