Solved

Parssing Template Nested Ifs

Posted on 2004-08-23
8
279 Views
Last Modified: 2006-11-17
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
Comment
Question by:stakadush
  • 3
  • 3
  • 2
8 Comments
 
LVL 48

Expert Comment

by:hernst42
ID: 11878336
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
 
LVL 3

Expert Comment

by:Boris Aranovich
ID: 11878442
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
 
LVL 48

Expert Comment

by:hernst42
ID: 11878591
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
 
LVL 3

Expert Comment

by:Boris Aranovich
ID: 11878630
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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 1

Author Comment

by:stakadush
ID: 11878732
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
 
LVL 48

Accepted Solution

by:
hernst42 earned 500 total points
ID: 11878823
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
 
LVL 1

Author Comment

by:stakadush
ID: 11879372
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
 
LVL 1

Author Comment

by:stakadush
ID: 11879376
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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Part of the Global Positioning System A geocode (https://developers.google.com/maps/documentation/geocoding/) is the major subset of a GPS coordinate (http://en.wikipedia.org/wiki/Global_Positioning_System), the other parts being the altitude and t…
Since pre-biblical times, humans have sought ways to keep secrets, and share the secrets selectively.  This article explores the ways PHP can be used to hide and encrypt information.
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now