NestedIf

Summary: Provide nested if / nested conditionals
Version: 2008-04-24B
Prerequisites: (none I'm aware of)
Status: Deprecated (now in core)
Maintainer: Peter Bowers
Users: (View? / Edit)
Categories: Conditional Markup

Questions answered by this recipe

From Version 2.2.0-beta66 (2008-07-04) "nested if" capability is built into the PmWiki core.

note: see below for a note on the current core implementation of nested-if.

This section is optional; use it to indicate the types of questions (if any) this recipe is intended to answer.

  • PmWiki has a nice way of handling conditionals, but it doesn't ("didn't" - it does as of 2.2.0-beta66) allow nesting. How can I do nested if/then/else statements?

Description

Installation

Copy/paste the following code into your config.php:

## (:nestedif:)/(:nestedelse:)(:nestedifend:)
$nestedifpat = "/( \\(:if-?(\\w)\\s*\\b([^\n]*?):\\)
     ((?:
        (?:(?!\\(:(?:if|else)).)+
        |(?R)
     )*?)
     (?: \\(: (?:else-?\\2) \\s* :\\)
       ((?:
          (?:(?!\\(:(?:if|else)).)+
          |(?R)
       )*?)
     )?
     (?: \\(: (?:if-?\\2-?end) \\s* :\\) )
    )/seix";
Markup('nestedif', '>if', $nestedifpat, "CondText3(\$pagename, PSS('$3'), PSS('$4'), PSS('$5'))");

function CondText3($pagename, $condspec, $condtext, $elsetext) {
  global $Conditions;
  #echo "condspec=$condspec<br>\ncondtext=$condtext<br>\nelsetext=$elsetext<br>\n";
  if (!preg_match("/^\\s*(!?)\\s*(\\S*)\\s*(.*?)\\s*$/", $condspec, $match)) 
      echo "ERROR: No Match on condspec \"$condspec\"<br>\n";
  list($x, $not, $condname, $condparm) = $match;
  if (!isset($Conditions[$condname])) return $condtext;
  $tf = @eval("return ({$Conditions[$condname]});");
  if ($tf xor $not) return $condtext;
  else return $elsetext;
}

Notes

(On the same day this recipe was released there was a very brief discussion on the users forum and it was decided that an alternate implementation was going to be put in core. So probably you want to wait and use what PM comes up with unless you urgently need a nested if immediately.)

Conditions are identical to whatever (:if ...:) would accept as the same code is used.

The character following each of the terms can be anything which matches \w (letter, digit, etc.) but it must be exactly the same for all corresponding terms. In other words, if your (:if0 ...:) is using 0 then your (:else0:) also must use 0 -- otherwise the regex won't match and your code will just disappear. POOF!

An example of the markup to show how it can be nested:

(:if0 name Test.*:)pos0(:if1 group Test2:)pos1(:else1:)pos2(:if1end:)(:else0:)pos3(:ifA group Test:)pos4(:elseA:)pos5(:ifAend:)(:if0end:)

The same placed on multiple lines and indented so you can see it more clearly:

(:if0 name Test.*:)
   pos0
   (:if1 group Test2:)
      pos1
   (:else1:)
      pos2
   (:if1end:)
(:else0:)
   pos3
   (:ifA group Test:)
      pos4
   (:elseA:)
      pos5
   (:ifAend:)
(:if0end:)

Release Notes

  • 2008-04-24 - Initial Release
  • 2008-04-24B- Changed syntax from n-if to if0

See Also

Contributors

Peter Bowers

I suppose it goes without saying, but most code here is borrowed from and built upon the foundation of PM's work.

Comments

  • Will there be a way to use an (:elseif:)? seems to make it a bit more complicated... overtones99 July 21, 2008, at 04:44 AM
  • on occasion, i've found that having nestedif execute after if ('>if') doesn't always work. so far, having it execute at the same time ('if') seems to work better... overtones99 August 04, 2008, at 10:22 PM

No letters allowed in current core-implementation of NestedIf
Note that the current pmwiki release (as of 2.2.0-beta67) includes Nested-If in the core, but does not allow the use of letters in the if statement, for instance:

# this works:
(:if1 false:)part1 true(:else1:)part1 false(:if2 true:)part2 true(:if2end:)(:if1end:)
# but this doesn't:
(:ifA false:)partA true(:elseA:)partA false(:ifB true:)partB true(:ifBend:)(:ifAend:)

Pm offered the following code to add to your config.php if you would like to enable the latter [(:if followed by one capital letter] -- it also enables nested-ifs that have more than one number, for instance (:if345 ...:):

          
	  $CondTextPattern =   
	    "/ \\(:if (\d*|[A-Z]) (?:end)? \\b[^\n]*?:\\)
		 .*?
		 (?: \\(: (?:if\\1|if\\1end) \\s* :\\)
		 |   (?=\\(:(?:if\\1|if\\1end)\\b[^\n]*?:\\) | $)
		 )
	     /seix";

overtones99 August 18, 2008, at 06:49 PM

User notes? : If you use, used or reviewed this recipe, you can add your name. These statistics appear in the Cookbook listings and will help newcomers browsing through the wiki.