1

I am in a middle of writing a project which has a template engine and some new defined tags like LOOP or IF and etc ...

Assume this is a block of template that PHP should process and convert to a PHP script:

<LOOP products>
    {{name}}
    {{id}}

    <LOOP comments>
        {{name}}
    </LOOP>

    {{quantity}}
</LOOP>

I want to convert all {{variables}} to print them out based on the properties of the loop variable, But I want to exclude inner LOOP tags for each loop.

Because the first LOOP's {{name}} tag should be $product->name and second LOOP's name should be $comment->name

This regex will convert all {{variables}} to first LOOP variable which is product.

$pattern = '/\s*\{\{(\w+)+\}\}\s*/';

Above output is

<LOOP products>
    {{name}} // $product->name
    {{id}} // $product->id

    <LOOP comments>
        {{name}} // $product->name ! <-- this {{variable}} should 
                 // be exculde of first loop converting.
    </LOOP>

    {{quantity}} // $product->quantity
</LOOP>

UPDATE

I also tried this:

(?!<LOOP[^>]*?>)\{\{(\w+)+\}\}(?![^<]*?</LOOP>)
// this works for 2 level of nested LOOPs.
// when I add another LOOP as third level ...
// ... contents of level2 are changing too, which is not corrent.
// ONLY first level should change.
cincodenada
  • 2,877
  • 25
  • 35
Pars
  • 4,932
  • 10
  • 50
  • 88

2 Answers2

2

you should first create a data tree from your text. after that you can apply the variable substitutions.

  1. search for the loop tags and split the document so you get a data structure like this:

    • LOOP: products
      • TEXT: {{name}} {{id}}
      • LOOP: comments
        • TEXT: {{name}}
      • TEXT: {{quantity}}
  2. go through all LOOP data entries and substitute all their TEXT-strings with your regex

  3. rebuild a text document by traversing the data structure

this will give you great flexibility when enhancing your template system. it will also be easier to maintain.

dreamlab
  • 3,321
  • 20
  • 23
1

Dreamlab is correct: don't try to parse XML/HTML with regex. Use an XML/HTML parser to process the data, and exclude the inner loops that way. This is an especially complex problem to solve with regexes that becomes surprisingly easy when you use the proper tools for the job. In your case, throw your XML into SimpleXML and iterate through the tree or use some XPath.

When regexes are your hammer, everything sometimes looks like a nail, but it's a really bad tool for a lot of situations - and a particularly terrible tool for your problem. Regex just isn't built to solve this kind of problem, and you will find nothing but pain if you attempt to do so.

A sidenote: It seems like you might be trying to invent a new templating language as well. If that's the case, you probably don't need to. Bundle Mustache or Smarty or Twig or any of the other numerous templating engines that already exist and are well-tested and functional.

It sounds like you may be writing some sort of framework, so this may not be applicable, but depending on your use case, you can just use PHP, since PHP is a templating language:

<?php for($products as $p): ?>
    <?=$p['name']?>
    <?=$p['id']?>

    <?php for($p['comments'] as $c): ?>
        <?=$c['name']?>
    <?php endforeach ?>

    <?=$p['quantity']?>
<?php endforeach ?>
Community
  • 1
  • 1
cincodenada
  • 2,877
  • 25
  • 35