Create your own HTML widgets with PHP
(Page 2 out of 4)Using an HTML parser
Up till now we've only been using some simple regular expressions to catch our custom tags, and then replacing it with simple HTML. But we haven't been able to use attributes in our own custom tags yet, like a regular HTML tag, so let's make that possible.
For this to happen, we're going to have to parse our custom tags using an HTML parser. There are plenty of PHP-based HTML parsers on the internet, but I'm using one that I wrote myself, and can be found in the PHPit Codesnippet Database. Here's a quick example of the HTML parser:
include ('htmlparser.php');
ob_start ();
?>
HTML Parser Demonstration
This script demonstrates the HTML parser.
// Get HTML of page
$html = ob_get_contents();
// Parse HTML
$parser = new HTML_Parser();
$output = $parser->parse($html);
// Any errors?
if ($parser->xml_error == true) {
echo 'XML Error: ' . $parser->xml_error_string . ' on line ' . $parser->xml_error_line_number;
}
// Show result
show ($output);
function show($data, $func = "print_r", $return_str = false){
ob_start();
$func($data);
$output = ''
.htmlspecialchars(ob_get_contents()).'';
ob_end_clean();
if($return_str) return $output; else echo $output;
}
?>
If you run the above example, you will notice that the HTML parser changes the HTML into a PHP array structure, and parses the attributes of each tag as well. This will come in handy for our custom tags.
The only downside of this HTML parser, and almost any PHP parser, is that the HTML must be correctly formatted. If you miss a tag or make any XML mistake, the parser will fail. That's why it's very important that the HTML code for your own custom tags are written with great care so that it's valid
Let's try and parse the attributes on our own custom tag now. See the example below.
include ('htmlparser.php');
function parse_mytag($content) {
// Find the tags
preg_match_all('/\<mytag([^>]*)\>(.*?)\<\/mytag\>/is', $content, $matches);
// Loop through each tag
for ($i=0; $i < count($matches['0']); $i++) {
// Get tag HTML
$html = $matches['0'][$i];
// Parse tag
$parser = new HTML_Parser();
$output = $parser->parse($html);
// XML Error?
if ($parser->xml_error == true) {
$error = 'XML Error: ' . $parser->xml_error_string . ' on line ' . $parser->xml_error_line_number;
$content = str_replace($html, $error, $content);
continue;
}
// Get structure of custom tag
$tag = $output['0'];
// Get color attribute
if (!empty($tag['attr']['COLOR'])) {
$color = $tag['attr']['COLOR'];
} else {
$color = 'black';
}
// Get text (that's the innerHTML of our tag)
$text = $tag['innerhtml'];
// Create replacement HTML
$new = '$color . '">';
$new .= $text;
$new .= '';
// Replace with actual HTML
$content = str_replace($html, $new, $content);
}
return $content;
}
ob_start ('parse_mytag');
?>
Here is my green widget:
Here is my orange widget:
Here is my black widget:
Here is a widget that will cause an error:
Here is my brown widget:
Here is my blue widget:
As you can see, it's now possible to specify the color of the text using the color attribute on our own custom tag. In the callback function we use the HTML parser to parse our custom tag, and then get the value of the color attribute from the array structure.
By parsing the HTML into a structure, it also opens another possibility. We can now look for sub tags in our custom tag and use them to do something. The below example demonstrates this:
include ('htmlparser.php');
function parse_mytag($content) {
// Find the tags
preg_match_all('/\<mytag([^>]*)\>(.*?)\<\/mytag\>/is', $content, $matches);
// Loop through each tag
for ($i=0; $i < count($matches['0']); $i++) {
// Get tag HTML
$html = $matches['0'][$i];
// Parse tag
$parser = new HTML_Parser();
$output = $parser->parse($html);
// XML Error?
if ($parser->xml_error == true) {
$error = 'XML Error: ' . $parser->xml_error_string . ' on line ' . $parser->xml_error_line_number;
$content = str_replace($html, $error, $content);
continue;
}
// Get structure of custom tag
$tag = $output['0'];
$text = $tag['tagData'];
// Parse sub tags
$children = (isset($tag['children'])) ? $tag['children'] : array();
foreach ($children as $subtag) {
// Font-size sub tag?
if ($subtag['name'] == 'FONT_SIZE') {
$font_size = $subtag['innerhtml'];
}
}
if (empty($font_size)) { $font_size = '120%'; }
// Create replacement HTML
$new = '$font_size . ';">';
$new .= $text;
$new .= '';
// Replace with actual HTML
$content = str_replace($html, $new, $content);
$font_size = '';
}
return $content;
}
ob_start ('parse_mytag');
?>
Here is my 160% widget:
Hello World
Here is my 140% widget:
Hello World
Here is my 120% widget:
Hello World
Here is my 100% widget:
Hello World
As you can see in the above example, we've created a custom sub tag called 'font_size' which can be used to define the font size of our message. Another thing worth noting is that we're now using tagData for the text in our tag instead of innerHTML. Since the innerHTML of our tag now also contains the custom sub tag, we have to use the tagData, since we only want the text.
So far we've only looked at some really simple and largely pointless examples, so let's create a useful HTML widget which can be used to simplify our pages. We're going to create a Repeater Control, which can be used to display an array, without having to loop through it.
June 20th, 2006 at 2:41 pm
[…] HTML * that contains the subtags and * It replaces the subtags with the key & value from an associative array. * You must bind the widget to the array through * Example: * ’Elijah Wood’,’Aragorn’=>’Viggo Mortensen’) * $repeaterWidget->bind(’cast’,$array))?> * * * : *
* * * Will output the html: * Frodo:: Elijah Wood *
* Aragorn:: Viggo Mortensen *
* * @author RosSoft * @version 0.1 * @license MIT * * @link http://phpit.net/article/create-html-widgets-php/4/ */require_once(dirname(__FILE__) . DS . ‘widget_helper.php’);class RepeaterWidgetHelper extends WidgetHelper{ //main tags name => array subtags var $tag=array( ‘repeater:repeater’=>array(’repeater:key’,’repeater:value’) ); function tag_repeater_repeater($attr,$inner_html) { $array=$this->_get_bound($attr[’array’]); […]