Reputation: 4600
In a variant of this question, I want to render a multiline string into an HTML table using Thymeleaf.
That is, how do I convert a string like
Cronut fixie tousled migas.
Whatever neutra offal fanny pack, photo booth kitsch bespoke hammock swag.
Keffiyeh yuccie meditation mustache cornhole paleo.
into
<table class="table">
<tr>
<td>Cronut fixie tousled migas.</td>
</tr>
<tr>
<td>Whatever neutra offal fanny pack, photo booth kitsch bespoke hammock swag.</td>
</tr>
<tr>
<td>Keffiyeh yuccie meditation mustache cornhole paleo.</td>
</tr>
</table>
Upvotes: 0
Views: 3653
Reputation: 6335
I originally posted this answer on a previous SO question but this one also seems to pop up. I've modified it to output a table instead of just newlines.
It's possible to do this with a custom dialect and attribute processor to handle doing this without a lot of inline SpEl or hacks.
Creating a Custom Attribute Processor
public class NewlineAttrProcessor extends AbstractUnescapedTextChildModifierAttrProcessor
{
public NewlineAttrProcessor()
{
super("nl2br");
}
@Override
protected String getText(Arguments arguments, Element element, String attributeName)
{
final Configuration configuration = arguments.getConfiguration();
final IStandardExpressionParser parser =
StandardExpressions.getExpressionParser(configuration);
final String attributeValue = element.getAttributeValue(attributeName);
final IStandardExpression expression =
parser.parseExpression(configuration, arguments, attributeValue);
final String value = (String)expression.execute(configuration, arguments);
final String[] lines = StringUtils.split(value, "\n");
return "<table><td>" + StringUtils.join(lines, "</td><td>") + "</td></table>";
}
@Override
public int getPrecedence()
{
return 10000;
}
}
You have to extend the AbstractUnescapedTextChildModifierAttrProcessor
processor or else you'll get the html entity tags for <table>...</table>
and you won't actually get the HTML.
Creating a custom dialect
To implement a custom dialect you need a dialect class like so:
public class MyCustomDialect extends AbstractDialect
{
@Override
public String getPrefix()
{
return "cd";
}
@Override
public Set<IProcessor> getProcessors()
{
final Set<IProcessor> processors = new HashSet<>();
processors.add(new NewlineAttrProcessor());
return processors;
}
}
The getPrefix
method return value is what you would use to call any custom processors that you make. For example, Thymeleaf uses th
. The custom processor we implemented above this is looking for nl2br
so to call it you would use the cd:nl2br
attribute instead of th:text
.
Registering your new dialect
In your main class, you just need to create a @Bean
that will return a new instance of your dialect class.
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Bean
public MyCustomDialect myCustomDialect()
{
return new MyCustomDialect();
}
}
Using your custom processor
Finally, in your template file you would have an HTML tag like this:
<div cd:nl2br="${myObject.myField}">MY MULTILINE FIELD</div>
For a more thorough guide to implementing custom dialects I recommend the Thymeleaf docs:
Upvotes: 1
Reputation: 4600
With the string contained in the model variable model.text
, a possible solution (when using the Spring dialect) is this:
<table>
<tr th:each="line : ${#strings.arraySplit(model.text, T(org.apache.commons.lang3.StringUtils).LF)}">
<td th:text="${line}"></td>
</tr>
</table>
The reason for using T(org.apache.commons.lang3.StringUtils).LF
instead of just \n
is that (as also described in this answer) SpEL escapes the backslash, and then decides to split on 'n'-letters instead of newlines.
Of course, one should also consider the solution of just splitting the string into an array directly in the controller (i.e. using plain Java).
Upvotes: 1