55

I have a String variable which contains carriage returns and new lines \r\n.

text = "Text1\r\nText2\r\nText3";

I'm presenting it using <h:outputtext>.

<h:outputText value="#{bean.text}" />

But it doesn't recognize the new line characters and shows as below in webbrowser.

Text1 Text2 Text3

Why doesn't the <h:outputText> break \n into new lines?

What should I do? Do I have to replace \n with <br />?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Pellizon
  • 1,365
  • 2
  • 12
  • 26
  • You may need to get the system's value for the line seperator I.E. String line = System.getProperty("line.separator"); – Neil Locketz Feb 01 '13 at 13:36

3 Answers3

122

Linebreaks in HTML are represented by <br /> element, not by the \n character. Even more, open the average HTML source code by rightclick, View Source in browser and you'll "see" \n over all place. They are however not presented as such in the final HTML presentation. Only the <br /> will.

So, yes, you need to replace them by <br />. You can use JSTL functions for this:

<... xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions">

<h:outputText value="#{fn:replace(bean.text,'\n','&lt;br/&gt;')}" escape="false" />

Note: when using Apache EL instead of Oracle EL, double-escape the backslash as in \\n.

<h:outputText value="#{fn:replace(bean.text,'\\n','&lt;br/&gt;')}" escape="false" />

Otherwise you will face an exception with the message Failed to parse the expression with root cause org.apache.el.parser.ParseException: Encountered <ILLEGAL_CHARACTER>.

This all is however ugly and the escape="false" makes it sensitive to XSS attacks if the value comes from enduser input and you don't sanitize it beforehand. A better alternative is to keep using \n and set CSS white-space property to preformatted on the parent element. If you'd like to wrap lines inside the context of a block element, then set pre-wrap. Or if you'd like to collapse spaces and tabs as well, then set pre-line.

E.g.

<h:outputText value="#{bean.text}" styleClass="preformatted" />
.preformatted {
    white-space: pre-wrap;
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • It didn't worked for me using
     tag, but i made a function to replace \r\n to 
    , i didn't finished yet, but it seems that its gonna work. Thank you BalusC !
    – Pellizon Feb 01 '13 at 16:00
  • 2
    You're welcome. Using the `
    ` should also work. However, the default behavior of `
    ` tag can be manipulated by CSS. So if you have some 3rd party CSS which you don't have read or just did't understand at all, then it might have been the cause that the `
    ` doesn't preformat anymore.
    – BalusC Feb 01 '13 at 16:05
  • 1
    Thanks for the "white-space: pre;" idea! In some cases (such as mine) the value "pre-line" is even better, because I don't want to mess with the wrapping. – henko Jun 17 '13 at 17:49
  • The `white-space: pre-wrap` worked for me. The `fn:replace` didn't. – joker Mar 15 '18 at 13:57
  • For me that doesn't work and the
    gets printed out as text.
    – GarfieldKlon Aug 21 '18 at 16:08
  • @GarfieldKlon: Perhaps you didn't understand the answer. For `
    ` you need the first code snippet and for `\n` you need the second code snippet.
    – BalusC Aug 22 '18 at 07:17
  • @BalusC, you're right, I missed the part with 'keep using \n'... Thanks – GarfieldKlon Aug 22 '18 at 10:54
  • With namespace declaration `xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions"` and `value="#{fn:replace(bean.text,'\\n','<br/>')}" escape="false"` it worked for me. Thank you. – hogi Mar 12 '20 at 20:21
13

This is normal behaviour, in HTML consecutive whitespace such as spaces and linebreaks gets normalized so it displays just as a single space. You would get the same display if you included the text with linebreaks directly in the HTML source. To honor linebreaks in the the output you would have to wrap the text in pre tags or apply a stylesheet class:

<pre><h:outputText value="..."/></pre>

<div style="white-space: pre-wrap"><h:outputText value="..."/></div>

For other possible values for the white-space attribute look at this page: http://www.w3schools.com/cssref/pr_text_white-space.asp

Jörn Horstmann
  • 33,639
  • 11
  • 75
  • 118
6

The previous answers caused problems for me for large amounts of text, like extremely wide output (no text wrap), which style="white-space: pre-wrap" did not fix; or it just displayed the &lt;br/&gt; as text, not as a line ending.

In the end I used the h:inputTextarea component to display the text and made it 'read only' which worked straight off without replacing the line breaks, nor having to use the extra styles or styleClasses. And, it is resizeable to suit the user's needs, which is a bonus.

<h:inputTextarea cols="70" rows="10" readonly="true" value="#{bean.text}" /> 

For small amounts of text, I found the pre-wrap option, as suggested by henko above, to work well.

Community
  • 1
  • 1
Robbie62
  • 221
  • 3
  • 14