...

View Full Version : Conditionals in a Template - Regex



thesmart1
08-14-2008, 10:36 PM
I'm working on a template parser. I have variables done, but conditionals (if, elseif, else) are confusing me. I'm using preg_replace to parse everything, but I'm not very good with regex. I got if's to work with this:

preg_replace(array('/\{L_(\w+)\}/e', '/(<!-- IF C_([\w]+) -->)(.*)(<!-- ENDIF -->)/se'), array('$this->variables["$1"]', '(($this->conditionals["$2"])?trim("$3", "\n"):"")'), $file_contents);But now I'm trying to add else (and eventually I'll add elseif). I have this line to try to do that:

preg_replace(array('/\{L_(\w+)\}/e', '/(<!-- IF C_([\w]+) -->)(.*)([^<!-- ELSE -->.*])(<!-- ENDIF -->)/se'), array('$this->variables["$1"]', '(($this->conditionals["$2"])?trim("$3", "\n"):trim("$3", "\n"))'), $file_contents);The entire conditional code in the template (between "<!-- IF C_conditional_name -->" and "<!-- ENDIF -->") is put in $3 because of the "(.*)", and I don't know how to make that exclude "<!-- ELSE -->". Also, my regex to parse an optional "<!-- ELSE -->" is probably wrong. So can anyone help me exclude "<!-- ELSE -->" from the first "(.*)"?

And some background info on this code: It is a class, and $this->variables is an associative array of {L_xx} var names and values and $this->conditionals is an associative array of conditional value names and values (i.e., if $this->conditionals['sample'] is true, so is C_sample in the template).

dumpfi
08-15-2008, 10:07 AM
Do a non-greedy match with .*? in your regex.

dumpfi

thesmart1
08-15-2008, 07:43 PM
I have '/(<!-- IF C_([\w]+) -->)(.*?)([^<!-- ELSE -->.*])(<!-- ENDIF -->)/Use' as my regex for conditionals now, and I tried .*? and the U modifier by themselves and together. With this in my template file:

<!-- IF C_LOGGEDIN -->
<p>Welcome back!</p>
<!-- ELSE -->
<p>Please log in</p>
<!-- ENDIF -->

I get this as output in my third match:

<p>Welcome back!</p>
<!-- ELSE -->
<p>Please log in</p>

So either my regex is wrong (highly likely) or that didn't help (which I guess it should have..).

thesmart1
08-16-2008, 04:53 PM
OK, I rewrote my code a bit to parse out variables first, then find anything between "<!-- IF -->" and "<!-- ENDIF -->", and finally try to parse "<!-- ELSEIF -->"'s and an "<!-- ELSE -->" with a preg_replace_callback.


function parseTemplate() {
$file_contents = $this->loadTemplate();
//'(($this->conditionals["$2"])?trim("$3", "\n"):trim("$3", "\n"))'),
$temp = preg_replace('/\{L_(\w+)\}/e', '$this->variables["$1"]', $file_contents);
return preg_replace_callback('/(<!-- IF C_([\w]+) -->)(.*)(<!-- ENDIF -->)/s', array($this, "parseConditionals"), $temp);
}
function parseConditionals($matches) {
var_dump($matches);
preg_match_all('/(<!-- ELSE([\w]*) -->)(.*)/s', $matches[3], $matches2);
echo "\n\n";
var_dump($matches2);
}I used ELSE([\w]*) to let the function match ELSEIF's and ELSE's and put the details of the conditional in the matches array. Right now I'm just printing all the matches it can find; I'll finish this to work with the matches later.

And with that, I get:

array(5) {
[0]=>
string(125) "<!-- IF C_LOGGEDIN -->
<p>Welcome back!</p>
<!-- ELSEIF -->
<p>Eh, wha?</p>
<!-- ELSE --> <p>Please log in</p>
<!-- ENDIF -->"
[1]=>
string(22) "<!-- IF C_LOGGEDIN -->"
[2]=>
string(8) "LOGGEDIN"
[3]=>
string(89) "
<p>Welcome back!</p>
<!-- ELSEIF -->
<p>Eh, wha?</p>
<!-- ELSE -->
<p>Please log in</p>
"
[4]=>
string(14) "<!-- ENDIF -->"
}


array(4) {
[0]=>
array(1) {
[0]=>
string(67) "<!-- ELSEIF -->
<p>Eh, wha?</p>
<!-- ELSE -->
<p>Please log in</p>
"
}
[1]=>
array(1) {
[0]=>
string(15) "<!-- ELSEIF -->"
}
[2]=>
array(1) {
[0]=>
string(2) "IF"
}
[3]=>
array(1) {
[0]=>
string(52) "
<p>Eh, wha?</p>
<!-- ELSE -->
<p>Please log in</p>
"
}
}for this template:

<!-- IF C_LOGGEDIN -->
<p>Welcome back!</p>
<!-- ELSEIF -->
<p>Eh, wha?</p>
<!-- ELSE -->
<p>Please log in</p>
<!-- ENDIF -->So it's including the next match in each match it's parsing (in the preg_match_all). I tried a "?" and a "/U" modifier to make it ungreedy, but then I would get nothing matched for the "(.*)". Is there any other way to prevent this? Like using regex to get a string that doesn't include "<!-- ELSE" instead of "(.*)"?

thesmart1
08-31-2008, 07:16 AM
I have another idea that I think I'll try tomorrow, but I'm wondering now if I should replace template code with PHP code and use exec instead. That way I could cache templates like other template systems do, but it may open up a security issue of executing PHP code that's in the templates (if I don't trust the web designer to not write malicious PHP code :p). The overhead in the way I'm doing it now *shouldn't* be that great, since it's only a couple regex function calls, but exec'ing cached PHP code would definitely be faster. Anyone else have any thoughts on which method I should use?



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum