Whitespace in output

210 views
Skip to first unread message

Mark Rogers

unread,
Jan 11, 2010, 6:48:05 AM1/11/10
to Smarty Developers
I'm having a lot of problems controlling whitespace (specifically line
breaks) in my output from Smarty v3 (rev 3441).

Eg:
$smarty->assign('tmp',array(1=>'Test 1',2=>'Test 2',3=>'Test 3'));

{foreach $tmp as $k => $v}
{$k} = {$v}
{if $k == 2}Found 2{/if}
{/foreach}
END

What I want to see is:
1 = Test 1
2 = Test 2
Found 2
3 = Test 3
END

.. but what I get is:
1 = Test 1
2 = Test 2
Found 23 = Test 3
END

ie the line break after the {/if} gets lost. I can fix this by putting a
line break immediately before the {/if}, but I'm not sure this is
correct behaviour? It seems inconsistent with the other surviving line
breaks (eg the one after {/foreach})

If this is something that will always be ambiguous maybe there should be
a way for the template developer to resolve the ambiguity, perhaps by
passing a parameter to the {if}, {foreach}, etc?

--
Mark Rogers // More Solutions Ltd (Peterborough Office) // 0844 251 1450
Registered in England (0456 0902) @ 13 Clarke Rd, Milton Keynes, MK1 1LG

John Campbell

unread,
Jan 11, 2010, 11:18:13 AM1/11/10
to smarty-d...@googlegroups.com
I use smarty for email templates where spacing is important, and the
logic for truncating whitespace has never made much sense to me, but I
know from trial and error adding a space after the {/if} will fix your
specific problem.

Regards,
John Campbell

> --
> You received this message because you are subscribed to the Google Groups
> "Smarty Developers" group.
> To post to this group, send email to smarty-d...@googlegroups.com.
> To unsubscribe from this group, send email to
> smarty-develop...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/smarty-developers?hl=en.
>
>
>
>

Monte Ohrt

unread,
Jan 11, 2010, 11:26:23 AM1/11/10
to smarty-d...@googlegroups.com
The {strip} tags and whitespacefilter are meant for HTML tagged content.
You can use the striptags|wordwrap modifiers to strip out html tags and
wrap your paragraphs at 72 chars to help with plain-text email formatting.

Mark Rogers

unread,
Jan 11, 2010, 11:32:47 AM1/11/10
to Smarty Developers
(To the list this time...)

On 11/01/10 16:26, Monte Ohrt wrote:
> The {strip} tags and whitespacefilter are meant for HTML tagged
> content. You can use the striptags|wordwrap modifiers to strip out
> html tags and wrap your paragraphs at 72 chars to help with plain-text
> email formatting.

Given that Smarty is generally used to create HTML content, I think that
anything which makes "sense" in that environment should be the default,
however it would be useful to be able to control this behaviour when necessary.

In my specific case I need to generate an INI file structure, and whilst:
[test]
x=1

y=1
z=3
.. is valid, I'm trying to generate tidy output for humans to read.

What are the current "rules" for handling whitespace surrounding Smarty tags?

Monte Ohrt

unread,
Jan 11, 2010, 11:42:08 AM1/11/10
to smarty-d...@googlegroups.com
Generally, Smarty tries to output the templates exactly as written. If
you put whitespace in the template, you get whitespace in the output. I
know sometimes this creates undesirable results, such as:

{if $foo}
bar
{else}
baz
{/if}

Can generate unwanted blank lines in the output. One workaround is to
run this into the same line:

{if $foo}bar{else}baz{/if}

Is that what you are encountering?

Mark Rogers

unread,
Jan 11, 2010, 11:52:20 AM1/11/10
to smarty-d...@googlegroups.com
On 11/01/10 16:42, Monte Ohrt wrote:
> Generally, Smarty tries to output the templates exactly as written. If
> you put whitespace in the template, you get whitespace in the output.
> I know sometimes this creates undesirable results, such as:
>
> {if $foo}
> bar
> {else}
> baz
> {/if}
>
> Can generate unwanted blank lines in the output. One workaround is to
> run this into the same line:
>
> {if $foo}bar{else}baz{/if}
>
> Is that what you are encountering?

No.

$smarty->assign('tmp',array(1=>'Test 1',2=>'Test 2',3=>'Test 3'));

{foreach $tmp as $k => $v}
{$k} = {$v}
{if $k == 2}Found 2{/if}
{/foreach}
END

.. gives:

1 = Test 1
2 = Test 2
Found 23 = Test 3
END

Note the lost whitespace after {/if} but not after {/foreach}

Monte Ohrt

unread,
Jan 11, 2010, 11:56:02 AM1/11/10
to smarty-d...@googlegroups.com
Is this Smarty 2 or 3?

uwe.tews

unread,
Jan 11, 2010, 11:57:10 AM1/11/10
to Smarty Developers
FYI Smarty2 and Smarty3 are showing same behaviour.

Mark Rogers

unread,
Jan 11, 2010, 12:05:58 PM1/11/10
to smarty-d...@googlegroups.com
On 11/01/10 16:56, Monte Ohrt wrote:
> Is this Smarty 2 or 3?

Smarty 3, rev 3441

(I think you probably missed my original post on the subject which
included version etc)

Monte Ohrt

unread,
Jan 11, 2010, 12:39:12 PM1/11/10
to smarty-d...@googlegroups.com
Its technically a bug, its the same in Smarty 2. I think we'll make it
consistent, so a newline in the template always means a newline in the
output. This comes up as a topic of debate now and then, because
sometimes newlines are not wanted such as:

{if true}
foo
{/if}

Will generate the output:

\nfoo\n\n

Since there are three newlines in the source. But better to be
consistent than trying to fix every situation.

uwe.tews

unread,
Jan 11, 2010, 12:38:38 PM1/11/10
to Smarty Developers
The SVN was updated that {/if} at a line end does create now a newline
in the output,

Steve E

unread,
Jan 12, 2010, 5:03:38 AM1/12/10
to Smarty Developers
Just a thought, if this was a problem in Smarty 2 then there will be a
fair bit of template fixing to be done for people.

I noticed in this code though:

$smarty->assign('tmp',array(1=>'Test 1',2=>'Test 2',3=>'Test 3'));

{foreach $tmp as $k => $v}
{$k} = {$v}
{if $k == 2}Found 2{/if}
{/foreach}

If you want a new line after "Found 2", surely the way to do it is to
insert a newline BEFORE the {/if}?

So it would become:


{foreach $tmp as $k => $v}
{$k} = {$v}
{if $k == 2}Found 2
{/if}
{/foreach}

Personally I don't mind that the newline is removed after an {/if}
statement - some of my templates will end up with long, long
statements on a single line otherwise.

{if $a == 1}xxx{/if}{if $b == 12}yyy{/if}{if $c == 15}zzz{/if}

vs

{if $a == 1}xxx{/if}
{if $b == 12}yyy{/if}
{if $c == 15}zzz{/if}

although I applaud consistency, absolutely!

Here's the thing though, we all know that PHP removes the first
newline after ?> - aren't you changing this behaviour if you enforce a
newline after the {/if}?

Steve

Mark Rogers

unread,
Jan 12, 2010, 6:26:02 AM1/12/10
to smarty-d...@googlegroups.com
On 12/01/10 10:03, Steve E wrote:
> Just a thought, if this was a problem in Smarty 2 then there will be a
> fair bit of template fixing to be done for people.
>


My opinion is that whatever happens should be consistent so that you don't
have to test a template and experiment with adding carriage returns in various
places in order to work out what the output will be, but if that breaks
backwards compatibility in any way then it should only be done at major
version change (ie now), and only then if there is more benefit than pain -
the last thing I want is to be the cause of thousands of template changes to
correct the handling of whitespace!

Another solution would be a Smarty option to change how the handling is done?
I'm not sure how messy that would be to implement.

I really don't like that {/if} and {/foreach} don't do the same thing, though!

Martin B

unread,
Jan 12, 2010, 7:33:59 AM1/12/10
to smarty-d...@googlegroups.com

> Monte Ohrt schrieb:
Hello!
Just a idea to fix this issue.
What if Smarty adds a line break in the output if there is more content
afterwards an if there isnt already a linebreak after?
Is it possible to detect if there ist more content afterwards and if
there isnt a line break afterwards, and only in this case the line break
is added /passed to the output?
This would be the optimal behaviour, I think.
To keep backward compactibility it should be a Configuraton Option, if
possible.

Greets, Martin


Alain Williams

unread,
Jan 12, 2010, 7:41:40 AM1/12/10
to smarty-d...@googlegroups.com
On Tue, Jan 12, 2010 at 01:33:59PM +0100, Martin B wrote:
> Just a idea to fix this issue.
> What if Smarty adds a line break in the output if there is more content
> afterwards an if there isnt already a linebreak after?

+1

I do like to try to keep the output generated looking nice, even if
the HTML is not always seen. I also use smarty to generate things like
email text -- where the newlines are seen, at least in the text/plain
attachment.

--
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT Lecturer.
+44 (0) 787 668 0256 http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: http://www.phcomp.co.uk/contact.php
Past chairman of UKUUG: http://www.ukuug.org/
#include <std_disclaimer.h>

Monte Ohrt

unread,
Jan 12, 2010, 9:48:04 AM1/12/10
to smarty-d...@googlegroups.com

> although I applaud consistency, absolutely!
>
> Here's the thing though, we all know that PHP removes the first
> newline after ?> - aren't you changing this behaviour if you enforce a
> newline after the {/if}?
>
> Steve
>
>


Templates != PHP code. If there is a newline in the template, there
should be a newline in the output.

We have pondered the idea of making non-outputting tags behave in a way
that does not create a newline in the template, even if a newline exists
after the template tag. This behavior isn't trivial though.

Steve E

unread,
Jan 13, 2010, 6:32:12 AM1/13/10
to Smarty Developers
"Templates != PHP code." Point taken.

I would agree with your statement - "if there is a newline in the


template, there should be a newline in the output."

That would make it very consistent and very clear what to expect.

Steve

Mark Rogers

unread,
Jan 13, 2010, 7:08:50 AM1/13/10
to smarty-d...@googlegroups.com
On 13/01/10 11:32, Steve E wrote:
> "Templates != PHP code." Point taken.
>
> I would agree with your statement - "if there is a newline in the
> template, there should be a newline in the output."
>
> That would make it very consistent and very clear what to expect.
>

I think an exception should be made for smarty block tags that are alone
on a line apart from whitespace.

So:
Blah
{if $x == 1}
Blah
{if $y == 1}
Blah
{/if}
{if}
End

should output
Blah
Blah
Blah
End
.. assuming $x = $y = 1

Monte Ohrt

unread,
Jan 14, 2010, 3:07:06 PM1/14/10
to smarty-d...@googlegroups.com
This discussion comes up every few years, and we always circle around to
the same conclusion.

And that is, the Smarty 2 behavior is the lesser of two evils, and it
works better in most situations. So the general rule is:

* If a built-in tag creates no output, it will not create a newline in
the output if it ends a line. That includes tags such as {if} {else}
{/if} {foreach} {/foreach} etc.

So for example:

Test 1
{if $foo}
Test 2
{/if}
Test 3

Will produce the output:

Test 1
Test 2
Test 3

or:

Test 1
Test 3

That is, no extra newlines generated by the {if} tags. Now, this creates
an issue with this syntax:

Test 1
{if $foo}Test 2{/if}
Test 3

now the result when $foo is true:

Test 1
Test 2Test3

Probably not exactly what you were after, but this is a result of the
behavior of non-output tags. PHP tags eat newlines for the exact same
reasoning, although Smarty does its best to make this transparent.

So to fix the above situation, the best solution is to split the line up:

Test 1
{if $foo}
Test 2
{/if}
Test 3

and you get what you are after.

John Campbell

unread,
Jan 14, 2010, 3:24:22 PM1/14/10
to smarty-d...@googlegroups.com
On Thu, Jan 14, 2010 at 3:07 PM, Monte Ohrt <mo...@ohrt.com> wrote:
> Test 1
> {if $foo}
> Test 2
> {/if}
> Test 3
>
> and you get what you are after.

This seems to work at first, but it still mangles the html tabs

<div>
{if $foo}
<span>baz</span>
{/if}
Test2
Test3
</div>

becomes:
<div>
<span>baz</span>
Test2
Test3
</div>

Which is not quite right... the spaces double up. If there was a way
to munch the spaces before the tag, that would be great. Of course, I
could do this with a prefilter.

-John Campbell

Monte Ohrt

unread,
Jan 14, 2010, 3:28:25 PM1/14/10
to smarty-d...@googlegroups.com
Yes Smarty is not going to know where you do and do not want spaces at
the beginning before tags. You can use the whitespace output filter that
comes with Smarty to do some post-opt spacing cleanup if that helps.

Mark Rogers

unread,
Jan 15, 2010, 4:07:47 AM1/15/10
to smarty-d...@googlegroups.com
On 14/01/10 20:07, Monte Ohrt wrote:
> This discussion comes up every few years, and we always circle around
> to the same conclusion.
>
> And that is, the Smarty 2 behavior is the lesser of two evils, and it
> works better in most situations. So the general rule is:
>
> * If a built-in tag creates no output, it will not create a newline in
> the output if it ends a line. That includes tags such as {if} {else}
> {/if} {foreach} {/foreach} etc.

If this is where the discussion ends, I'm happy (there's a simple rule
so I can learn what to expect). However I'll have one last go at an
alternative, which is basically what I suggested earlier:

* If a built-in tag creates no output, and is on it's own (except
whitespace) on a line, then the entire line will not generate any output.

So this example:

> Test 1
> {if $foo}
> Test 2
> {/if}
> Test 3

Will still produce the same output, and John's example:


> <div>
> {if $foo}
> <span>baz</span>
> {/if}
> Test2
> Test3
> </div>
>

.. will now work as he expected because the leading whitespace on the
{if} and {/if} lines will be swallowed because there's no other content
on those lines.

However:

Test1: {if $x}A{else}B{/if}
Test2: {if $y}A{else}B{/if}

.. would then generate
Test1: A
Test2: B
.. instead of
Test1: ATest2: B

And:
Number of Sheep: {$sheep} sheep
Number of Cows: {$cows} cow{if $cow != 1}s{/if}
Number of Pigs: {$pigs} pig{if $pig != 1}s{/if}.
Number of Cattle: {$cattle} cattle
.. would give:
Number of Sheep: 6 sheep
Number of Cows: 1 cow
Number of Pigs: 5 pigs.
Number of Cattle: 2 cattle
.. not:
Number of Sheep: 6 sheep
Number of Cows: 1 cowNumber of Pigs: 5 pigs.
Number of Cattle: 2 cattle

Is there a good example of where this rule doesn't do what would be
expected?

Bryan Drewery

unread,
Jan 15, 2010, 7:40:40 AM1/15/10
to smarty-d...@googlegroups.com

Mark Rogers wrote:
> If this is where the discussion ends, I'm happy (there's a simple rule
> so I can learn what to expect). However I'll have one last go at an
> alternative, which is basically what I suggested earlier:
>
> * If a built-in tag creates no output, and is on it's own (except
> whitespace) on a line, then the entire line will not generate any output.
>
I'm all for this. Newlines/whitespace is hard to predict currently,
which makes testing expected output rather challenging. If there's 1
line with an {if} I always expect that line to have no output.

Bryan

Monte Ohrt

unread,
Jan 15, 2010, 9:07:46 AM1/15/10
to smarty-d...@googlegroups.com
The rule sounds fine, it's the implementation that is a gotcha. The tag
needs to know whether or not to generate a newline, and the lexer is not
always going to be able to figure out what context you are looking for.
It's exactly the same issue with straight PHP. <?php?> tags always eat a
newline, and you'll end up with the same conditions for the same reasons.

Mark Rogers

unread,
Jan 15, 2010, 9:39:09 AM1/15/10
to smarty-d...@googlegroups.com
On 15/01/10 14:07, Monte Ohrt wrote:
> The rule sounds fine, it's the implementation that is a gotcha. The
> tag needs to know whether or not to generate a newline, and the lexer
> is not always going to be able to figure out what context you are
> looking for. It's exactly the same issue with straight PHP. <?php?>
> tags always eat a newline, and you'll end up with the same conditions
> for the same reasons.


Where is the existing rule handled? Without looking through the code the
difference between not outputting a newline if the tag is at the end of
a line, vs not outputting a newline if the tag is on a line with only
whitespace, seems simple, but I know that it's never quite that easy!

Monte Ohrt

unread,
Jan 15, 2010, 9:54:23 AM1/15/10
to smarty-d...@googlegroups.com
These tags just eat the newline immediately following the tag (if there
is one.)

Monte Ohrt

unread,
Jan 15, 2010, 9:55:54 AM1/15/10
to smarty-d...@googlegroups.com
Let me re-iterate: these tags do not generate a newline. So {if ...}
compiles to <?php if(): ?> and PHP takes care of eating the following
newline if one exists in the template.

Mark Rogers

unread,
Jan 15, 2010, 10:08:20 AM1/15/10
to smarty-d...@googlegroups.com
On 15/01/10 14:55, Monte Ohrt wrote:
> Let me re-iterate: these tags do not generate a newline. So {if ...}
> compiles to <?php if(): ?> and PHP takes care of eating the following
> newline if one exists in the template.

Understood! Thanks for the explanation.

Thue Janus Kristensen

unread,
Jan 15, 2010, 12:18:46 PM1/15/10
to smarty-d...@googlegroups.com
That should be possible to implement. I may do it, if I find the time.

Regards, Thue

--
You received this message because you are subscribed to the Google Groups "Smarty Developers" group.
To post to this group, send email to smarty-d...@googlegroups.com.
To unsubscribe from this group, send email to smarty-develop...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/smarty-developers?hl=en.




Reply all
Reply to author
Forward
0 new messages