...

View Full Version : Templates, dealing with nested tags?



Jak-S
02-10-2006, 02:56 PM
Hi,

Iím trying to write a simple template parser for an application Iím building, but I am stuck on something that seems like it should be obvious, but I cant work it out for the life of me.

Say I have a template that looks like this:


Some text here
{loop:products}
Text
{/products}
Some more text

I can easily write a function with preg_replace_callback that will find all the loops and repeat the contents the number of time, or insert data etc., what goes in the loop is irrelevant at the moment. The regex looks like this:


/{loop:(.*?)}(.*?){\/loop}/is

Where Iím stuck is working out how to deal with something like this:


Some text here
{loop:products}
Text
{loop:prices}
Text
{/ loop}
{/ loop}
Some more text

Because the regex will return:


{loop:products}
Text
{loop:prices}
Text
{/ loop}

I get the feeling this canít be done with preg_replace_callback, but can someone point me in the right direction on how to deal with this? Being able to nest tags seems a fundamental part of any template system, mark-up language etc. I just donít have a clue how to deal with it.

Thanks in advance, any help will be MUCH appreciated.

Jack

Jak-S
02-12-2006, 03:18 PM
No one? :confused:

ralph l mayo
02-12-2006, 04:47 PM
Remove the last question mark to make the match greedy (matching characters up until the last instead of the first match) and I think you get what you want:

/{loop:(.*?)}(.*){\/loop}/is

Jak-S
02-12-2006, 04:52 PM
Yeah, but that would screw up when it comes to this:



{loop:products}
Text
{/products}

{loop:users}
Text
{/products}


It wouldnt be able to treat them as separate loops, it would make that one match, rather than two.

fci
02-12-2006, 05:07 PM
ok, here is what I came up with.
it's not a complete solution but i figure it is close enough to what you need that you can customize (i.e., set callback functions for what you want to do with the different type of blocks). only caveat is you'd want to have the left curly braces { to be htmlentities or it'd likely break.

<?php

$str=<<<TPL
Some text here
{loop:products}
Text
{loop:prices1}
Text
{/ loop}
asdfasdf
{loop:prices2}
Text
{loop:prices3}
Text
{loop:prices4}
Text
{/ loop}
{/ loop}
{/ loop}
{/ loop}
finally Some more text
TPL;

# fun with regex
preg_match_all("/([^{]*?)?\{(\/ )?loop(:[^}]+)?\}([^{]*)?/im", $str, $matches);

#print_r($matches);
print '<pre>';

$len = count($matches[0]);

# assign better variable names
$before_text =&$matches[1];
$after_text =&$matches[4];

$start_loops =&$matches[3];
$end_loops =&$matches[2];

$in_loop = -1;
$depth = 0;
$loops = array();
$delimit = " - "; # used to see the indentation

for ($x=0; $x<$len; $x++) {
$txt = preg_replace("/\s+/", "", $before_text[$x]); // remove all whitepsace
$is_before = !empty($txt);
$txt = preg_replace("/\s+/", "", $after_text[$x]); // remove all whitepsace
$is_after = !empty($txt);

if ($is_before) {
print "before: $before_text[$x]\r\n";
}

// see if this is a start loop
if ($start_loops[$x]!="") {

array_push($loops, $x);


$msg = '';

// track the depth level of the loops
if ($in_loop!=-1 || $depth>0) {
$depth++;
$msg = "(nested)";
}

# execute what you want here
# for now just display what's going on
print str_repeat($delimit, $depth);
print "Starting loop $x at depth $x $msg\r\n";

$in_loop = $x;

// else it might be closing the loop
} else if ($end_loops[$x]!="") {
$b = array_pop($loops);
# execute what you want here
# for now just display what's going on
print str_repeat($delimit, $depth);
print "Closing loop at depth $depth, loop $b\r\n";

$depth--;
}

if ($is_after) {
print "after: $after_text[$x]\r\n";
}

}

?>

ralph l mayo
02-12-2006, 05:07 PM
Yeah, forgot about that. I wrestled with the same problem back when I used a regex template engine. I'll try to remember what I did to sort it and comment later, but for the record the whole thing turned out to be just a gigantic hassle and I'm advise you to switch to an engine based on XML or DOM (the latter of which, http://codingforums.com/showthread.php?t=76691), because they do a lot of the work of sorting the tags into logical structures for you.

edit: or woot, nevermind, a solution!

Jak-S
02-12-2006, 06:20 PM
fci:

cheers for the script, i donít have time to try it out right now, but i will have a look later on, see if i ca make sense of it. Thanks again, really is much appreciated.

ralph l mayo:

yeah, i did consider an xml based system, but it has to be compatible with php 4 and 5, and 4 requires an extension, i know thatís not really much of a problem, but im just trying to avoid it at the moment.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum