Link to home
Start Free TrialLog in
Avatar of stakadush
stakadush

asked on

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!
Avatar of hernst42
hernst42
Flag of Germany image

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 } ?>
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...
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.
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...
Avatar of stakadush
stakadush

ASKER

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! :)

ASKER CERTIFIED SOLUTION
Avatar of hernst42
hernst42
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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... :)
by the way, my system wouldn't work if i did <?php tags...eval would sream at me! :)
had to do just a simple <?