• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 294
  • Last Modified:

Parssing Template Nested Ifs

Hey :)

i have programmed a template system for a project i am working on. i am having problems when the template has nested ifs inside it. i can't think of a way to parse those ifs correctly.
here is an example (my template system tags are enclosed in %%):

%if_login%
     user logged in
     %if_user_admin%
           you are an admin! welcome....
     %end_if%

     here is some more text in case the user has logged in.....
%else%
      %if_logoff%
           you logged off succesfully!
      %end_if%

      you need to login...
      print login form here....
%end_if%

now the problem is i was trying to use the following regular expression to process the if statements:
$my_pattern = preg_replace("/%if_([^%]+)%(.*?)(?:%else%(.*?)|)%end_if%/ise", "\$this->process_if('\\1', '\\2', '\\3', \$iterate)", $my_pattern);

it works well if there are no nested ifs, but when it encounters a nested if, it takes the wrong %end_if% and all gets mixed up...i wanted to have a function that will not mind the number of if statements...
i tried using preg_split to split as follwos: preg_split('/(%(?:if_[^%]+|else)%)(.*?)/is',$data, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

and then looping on that but i am totally stuck! my head went blank...;)

any ideas on how to crack this one?!

cheers!
0
stakadush
Asked:
stakadush
  • 3
  • 3
  • 2
1 Solution
 
hernst42Commented:
I don't think that it is possible to do it with a regular expression to replace your syntax for nested conditions. Even if such a thing exists your evaluation of the code will not work, as the transformed nested condition will be in the string of the first condition. To make the nested thing work try to transform your template-code into PHP and evaluate that. e.g:

%if_login% => <?php if ($this->process_if('login') { ?>
%else% => <?php } else { ?>
%end_if% => <?php } ?>
0
 
Boris AranovichSenior Software EngineerCommented:
Try adding the 'U' modifier the to the regex, it will make it Ungreedy, though on the other hand, it may be the exactly opposite of wanted behaveour...
0
 
hernst42Commented:
Your templatesystem is not designed to work with nested conditions at them moment. If you get the replace correct that would be the result;

$this->process_if('login', '
     user logged in
     $this->process_if(\'user_admin\', \'
           you are an admin! welcome....
     \', \'\', $iterate)

     here is some more text in case the user has logged in.....
', '
      $this->process_if(\'logoff\', \'
           you logged off succesfully!
     \', \'\', $iterate)

      you need to login...
      print login form here....
', $iterate)

So how do evaluate the conditions inside the other blocks?

So to make your system work with nested conditions you need to rewrite your system so it uses a parser that can evalute the blocks or replace the template into PHP and there the conditions get evaluated.
0
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
Boris AranovichSenior Software EngineerCommented:
Actually, I think the parsin should be done recursively...
You need to get the IF condition by regex, and then call a function to parse everything inside it, that will parse everything inside if it has anything... amd so on.
Don't really have time now to write anything, but this is the guideline, hope someone can try to write it...
0
 
stakadushAuthor Commented:
well, this is actually what i was trying to do Nomaed...i was tryingn to grab everything with the preg_split, so i can tell when starts an if or an else clause, and then run it through a recursive function...
but i got confused and can't really find my hands and feet inside..
for example, i need to know for each if block which is it's parent...
then i need to count how many times if (or else) blocks were opened without a corresponding %end_if% block to know how deep inside the nested blocks i am, and when i find an %end_if% i need to go back a parent...but also, there can be two or more %end_if% one after the other, so i was trying to use preg_match_all(), and count how many (if any) %end_if% were found...but i'm lost at the point, as to how to create the array correctly...
here is an example of the recursive function i got so far...if someone could help me finish it so to have a good multi-dimension array of the if/else blocks, it would be great! ;)
this code was totally stopped in the middle, cause i got confused, so  somethings in it might not be necessary...

$data includes the raw data with the if blocks in it...

$ifs = preg_split('/(%(?:if_[^%]+|else)%)(.*?)/is', $data, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

$sorted_ifs = array();
$total_found = 0;
iterate_ifs($ifs, 0, $sorted_ifs, $total_found, $sorted_ifs);


echo print_r($sorted_ifs);

function iterate_ifs(&$ifs, $start_point, &$parent_array, &$total_found, &$sorted_ifs) {
      for ($i = $start_point; $i < count($ifs); $i++) {
            $iam = count($parent_array);
            if (preg_match('/%(if_[^%]+|else)%/', $ifs[$i], $matches)) {
                  $parent_array[$iam] = array();
                  $parent_array[$iam][0] = $matches[1];
                  iterate_ifs($ifs, $i+1, $parent_array[$iam], $total_found, $sorted_ifs);
            } else {
                  if (preg_match_all('/%end_if%/', $ifs[$i], $matches)) {
                        // what to do?!
                  }
                  $parent_array[$iam] = $ifs[$i];
            }
            $total_found++;
            if ($total_found >= count($ifs)) {
                  break;
            }
      }
}


by the way, using php is no option because the templates are for non-programmers...otherwise i would have used smarty, and save myself all the headache! :)

0
 
hernst42Commented:
You could use PHP to evaluate the conditions correctly in the template than writeing your own parser. After the conditions have been evaluated by PHP you have the output and then replace variables in the finished aoutput. The non-programmes don't need to know how the template is interpreted, evaluated.

Maybe you have to redifine the function process_if to it works with one argument.
Do a preg_replace for
%if_(\w+)% => <?php if ($this->process_if('\1') { ?>
%else% => <?php } else { ?>
%end_if% => <?php } ?>

do an
ob_start();
eval("?>$replacedTemplate<?php");
$evaluatedTemplate = ob_get_contents();
ob_end_clean();

And it will save you a lot of time and is easy to understand
0
 
stakadushAuthor Commented:
thank you hernst42! worked like a charm....:)
great idea by the way...it's good sometimes to get a different head on a problem, with a different view to a problem... :)
0
 
stakadushAuthor Commented:
by the way, my system wouldn't work if i did <?php tags...eval would sream at me! :)
had to do just a simple <?
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 3
  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now