I'm using Thymeleaf template engine with spring and I'd like to display text stored throught a multiline textarea.
In my database multiline string are store with "\n" like this : "Test1\nTest2\n...."
With th:text i've got : "Test1 Test2" with no line break.
How I can display line break using Thymeleaf and avoid manually "\n" replacing with < br/> and then avoid using th:utext (this open form to xss injection) ?
Thanks !
Two of your options:
Use th:utext - easy setup option, but harder to read and remember
Create a custom processor and dialect - more involved setup, but easier, more readable future use.
Option 1:
You can use th:utext if you escape the text using the expression utility method #strings.escapeXml( text ) to prevent XSS injection and unwanted formatting - http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#strings
To make this platform independent, you can use T(java.lang.System).getProperty('line.separator') to grab the line separator.
Using the existing Thymeleaf expression utilities, this works:
<p th:utext="${#strings.replace( #strings.escapeXml( text ),T(java.lang.System).getProperty('line.separator'),'<br />')}" ></p>
Option 2:
The API for this is now different in 3 (I wrote this tutorial for 2.1)
Hopefully you can combine the below logic with their official tutorial. One day maybe I'll have a minute to update this completely. But for now:
Here's the official Thymeleaf tutorial for creating your own dialect.
Once setup is complete, all you will need to do to accomplish escaped textline output with preserved line breaks:
<p fd:lstext="${ text }"></p>
The main piece doing the work is the processor. The following code will do the trick:
package com.foo.bar.thymeleaf.processors
import java.util.Collections;
import java.util.List;
import org.thymeleaf.Arguments;
import org.thymeleaf.Configuration;
import org.thymeleaf.dom.Element;
import org.thymeleaf.dom.Node;
import org.thymeleaf.dom.Text;
import org.thymeleaf.processor.attr.AbstractChildrenModifierAttrProcessor;
import org.thymeleaf.standard.expression.IStandardExpression;
import org.thymeleaf.standard.expression.IStandardExpressionParser;
import org.thymeleaf.standard.expression.StandardExpressions;
import org.unbescape.html.HtmlEscape;
public class HtmlEscapedWithLineSeparatorsProcessor extends
AbstractChildrenModifierAttrProcessor{
public HtmlEscapedWithLineSeparatorsProcessor(){
//only executes this processor for the attribute 'lstext'
super("lstext");
}
protected String getText( final Arguments arguments, final Element element,
final 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);
//return the escaped text with the line separator replaced with <br />
return HtmlEscape.escapeHtml4Xml( value ).replace( System.getProperty("line.separator"), "<br />" );
}
#Override
protected final List<Node> getModifiedChildren(
final Arguments arguments, final Element element, final String attributeName) {
final String text = getText(arguments, element, attributeName);
//Create new text node signifying that content is already escaped.
final Text newNode = new Text(text == null? "" : text, null, null, true);
// Setting this allows avoiding text inliners processing already generated text,
// which in turn avoids code injection.
newNode.setProcessable( false );
return Collections.singletonList((Node)newNode);
}
#Override
public int getPrecedence() {
// A value of 10000 is higher than any attribute in the SpringStandard dialect. So this attribute will execute after all other attributes from that dialect, if in the same tag.
return 11400;
}
}
Now that you have the processor, you need a custom dialect to add the processor to.
package com.foo.bar.thymeleaf.dialects;
import java.util.HashSet;
import java.util.Set;
import org.thymeleaf.dialect.AbstractDialect;
import org.thymeleaf.processor.IProcessor;
import com.foo.bar.thymeleaf.processors.HtmlEscapedWithLineSeparatorsProcessor;
public class FooDialect extends AbstractDialect{
public FooDialect(){
super();
}
//This is what all the dialect's attributes/tags will start with. So like.. fd:lstext="Hi David!<br />This is so much easier..."
public String getPrefix(){
return "fd";
}
//The processors.
#Override
public Set<IProcessor> getProcessors(){
final Set<IProcessor> processors = new HashSet<IProcessor>();
processors.add( new HtmlEscapedWithLineSeparatorsProcessor() );
return processors;
}
}
Now you need to add it to your xml or java configuration:
If you are writing a Spring MVC application, you just have to set it at the additionalDialects property of the Template Engine bean, so that it is added to the default SpringStandard dialect:
<bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
<property name="additionalDialects">
<set>
<bean class="com.foo.bar.thymeleaf.dialects.FooDialect"/>
</set>
</property>
</bean>
Or if you are using Spring and would rather use JavaConfig you can create a class annotated with #Configuration in your base package that contains the dialect as a managed bean:
package com.foo.bar;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.foo.bar.thymeleaf.dialects.FooDialect;
#Configuration
public class TemplatingConfig {
#Bean
public FooDialect fooDialect(){
return new FooDialect();
}
}
Here are some further references on creating custom processors and dialects: http://www.thymeleaf.org/doc/articles/sayhelloextendingthymeleaf5minutes.html , http://www.thymeleaf.org/doc/articles/sayhelloagainextendingthymeleafevenmore5minutes.html and http://www.thymeleaf.org/doc/tutorials/2.1/extendingthymeleaf.html
Try putting style="white-space: pre-line" on the element.
For example:
<span style="white-space: pre-line" th:text="${text}"></span>
You might also be interested in white-space: pre-wrap which also maintains consecutive spaces in addition to line breaks.
Avoid using th:utext if possible as it has serious security implications. If care is not taken, th:utext can create the possibility of XSS attacks.
Maybe not what the OP had in mind, but this works and prevents code injection:
<p data-th-utext="${#strings.replace(#strings.escapeXml(text),'
','<br>')}"></p>
(Using HTML5-style Thymeleaf.)
In my case escapeJava() returns unicode values for cyrillic symbols, so I wrap all in unescapeJava() method help to solve my problem.
<div class="text" th:utext="${#strings.unescapeJava(#strings.replace(#strings.escapeJava(comment.text),'\n','<br />'))}"></div>
If you are using jQuery in thymleaf, you can format your code using this:
$('#idyourdiv').val().replace(/\n\r?/g, '<br />')
Hope that answer can help you
Try this
<p th:utext="${#strings.replace(#strings.escapeJava(description),'\n','<br />')}" ></p>
You need to use th:utext and append break line to string.
My code is:
StringBuilder message = new StringBuilder();
message.append("some text");
message.append("<br>");
message.append("some text");
<span th:utext="${message}"></span>
Inspired by #DavidRoberts answer, I made a Thymeleaf dialect that makes it easy to keep the line breaks, if the css white-space property isn't an option.
It also bring support for BBCode if you want it.
You can either import it as a dependency (it's very light, and very easy to set up thanks to the starter project) or just use it as inspiration to make your own.
Check it out here :
https://github.com/oxayotl/meikik-project
Related
I'm deserializing a large XML file (not mine) and it contains custom entities defined as:
<!ENTITY math "mathematics">
and elements used this way:
<field>&math;</field>
When I try to deserialize it by:
XmlMapper xmlMapper = new XmlMapper();
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
return xmlMapper.readValue(classloader.getResourceAsStream("file.xml"), MyClass.class);
I get this error:
com.fasterxml.jackson.databind.JsonMappingException: Undeclared general entity "math"
I think it might be a security measure to prevent Xml External Entity injections.
Is there a way to mark these custom entities as valid? Like create an Enum for them or something?
If not, is there a flag to just parse these as Strings?
Update:
I was able to work around this problem by basically doing a find-replace on the text file. It's quite an ugly solution and if anyone has a better idea, I'm all ears. :)
I know it may be a little late, but just in case someone else is stuck on the same issue:
You have to set a custom XMLResolver as XMLInputFactory's property:
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.ctc.wstx.api.WstxInputProperties;
import javax.xml.stream.XMLResolver;
import javax.xml.stream.XMLStreamException;
var xmlMapper = new XmlMapper();
xmlMapper.getFactory().getXMLInputFactory().setProperty(
WstxInputProperties.P_UNDECLARED_ENTITY_RESOLVER,
new XMLResolver() {
#Override
public Object resolveEntity(String publicId, String systemId, String baseUri, String ns) throws XMLStreamException {
// replace the entity with a string of your choice, e.g.
switch (ns) {
case "nbsp":
return " ";
default:
return "";
}
// some useful tool is org.apache.commons.text.StringEscapeUtils
// e.g.
// return StringEscapeUtils.escapeXml10(StringEscapeUtils.unescapeHtml4('&' + ns + ';'));
}
}
);
// then xmlMapper.readValue....
Is there a way to return all the matched expressions?
Consider the following sentence
John Snow killed Ramsay Bolton
where
John-NNP, Snow-NNP, killed- VBD, Ramsay-NNP, Bolton-NNP
And I am using the following tag combination as rules
NNP-NNP
NNP-VBD
VBD-NNP
and expected matched words from the above rules are:
John Snow, Snow killed, killed Ramsay, Ramsay Bolton
But using the below code, I am getting only this as matched expression:
[John Snow, killed Ramsay]
Is there a way in stanford to get all the expected matching words from the sentence? This is the code and rule file I am using right now:
import com.factweavers.multiterm.SetNLPAnnotators;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.ling.tokensregex.CoreMapExpressionExtractor;
import edu.stanford.nlp.ling.tokensregex.Env;
import edu.stanford.nlp.ling.tokensregex.NodePattern;
import edu.stanford.nlp.ling.tokensregex.TokenSequencePattern;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.StanfordCoreNLP;
import edu.stanford.nlp.util.CoreMap;
import java.util.List;
import java.util.regex.Pattern;
public class StanfordTest {
public static void main(String[] args) {
String rulesFile="en.rules";
Env env = TokenSequencePattern.getNewEnv();
env.setDefaultStringMatchFlags(NodePattern.NORMALIZE);
env.setDefaultStringPatternFlags(Pattern.CASE_INSENSITIVE);
env.bind("collapseExtractionRules", false);
CoreMapExpressionExtractor extractor= CoreMapExpressionExtractor.createExtractorFromFiles(env, rulesFile);
String content="John Snow killed Ramsay Bolton";
Annotation document = new Annotation(content);
SetNLPAnnotators snlpa = new SetNLPAnnotators();
StanfordCoreNLP pipeline = snlpa.setAnnotators("tokenize, ssplit, pos, lemma, ner");
pipeline.annotate(document);
List<CoreMap> sentences = document.get(CoreAnnotations.SentencesAnnotation.class);
sentences.parallelStream().forEach(sentence -> {
System.out.println(extractor.extractExpressions(sentence));
});
}
}
en.rules
{
ruleType:"tokens",
pattern:([{tag:/VBD/}][ {tag:/NNP/}]),
result:"result1"
}
{
ruleType:"tokens",
pattern:([{tag:/NNP/}][ {tag:/VBD/}]),
result:"result2"
}
{
ruleType:"tokens",
pattern:([{tag:/NNP/}][ {tag:/NNP/}]),
result:"result3"
}
I think you need to create different extractors for different things you want.
The issue here is that when you have two part-of-speech tag rule sequences that overlap like this, the first one that gets matched absorbs the tokens preventing the second pattern from matching.
So if (NNP, NNP) is the first rule, "John Snow" gets matched. But then the Snow is not available to be matched with "Snow killed".
If you have a set of patterns that overlap like this, you should disentangle them and put them in separate extractors.
So you can have a (noun, verb) extractor, and a separate (noun, noun) extractor for instance.
I'm new to java 8 and meet a problem trouble me a lot:
I've a List like below:
List<objMain>
class objMain{
Long rid;
List<objUser> list;
String rname;
}
class objUser{
String userid;
}
now,I want get a new List like below:
List<objUserMain>
class objUserMain{
Long rid;
String rname;
String userid;
}
How can I do this by java 8 stream? Thanks anyone answer me.
It seems as though you want to map each objMain instance into an objUserMain type.
In order to accomplish the task at hand, you'll need to utilise flatMap along with map then collect to a list implementation.
Assuming you have getters and setter where necessary then you can perform the following logic to get the required result.
List<objUserMain> result =
objMainsList.stream()
.flatMap(obj -> obj.getList().stream().map(e -> {
objUserMain user = new objUserMain();
user.setRid(obj.getRid());
user.setRname(obj.getRname());
user.setUserid(e.getUserid());
return user;
})).collect(Collectors.toList());
You can do this using streams the following way
public static List convert(List existing, Function func) {
return existing.stream().map(func).collect(Collectors.toList());
}
The above method will help you to convert your list from one object type to another. The parameters to this is the initial object you want to convert and the method you want to use for conversion. Import the following in you main class
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.function.*;
Now call the method for conversion the following way in the main class that you are trying to convert
List result=convert(newList,
l->{
objUserMain r=new objUserMain();
r.rid=l.rid;
r.rname=l.rname;
r.userid=l.list.get(0).userid;
return r;});
System.out.println(result.get(0).rid);
System.out.println(result.get(0).rname);
System.out.println(result.get(0).userid);
The above is a mixture of lambda functions and streams to allow you to convert object from one type to another. Let me know if you have any queries then I am happy to help. Happy coding.
From all the searching and reading it’s clear that I need to call Platform.runLater() to change the GUI. It also appears I need to use the Runnable interface. Perhaps I should also use Tasks?
But I can’t figure out how exactly I should use them. Plus, I’m not sure which class I should put them in. I’m super new to JavaFX.
My trial JavaFX project has only a Label and a TextField. Label contains a question and the TextField is for answering. Simple enough.
I ran into the problem here:
The answer checking method is in a separate class. I can’t figure out how I can access the components of the GUI/FXML and change them. The methods in the other classes are static while the components of the GUI/FXML are non-static.
Since my actual project would have many quizzes, I'm keen on using separate classes for checking answers.
Only 3 small classes are relevant here:
The “Launcher” class which contains the main method.
The “ViewController” class for the FXML file as well as some methods.
The “Ans” class which has a method to check the answer input.
In which class should I put the Platform.runLater()? And how would the code be?
I’ll just share the code of the “Ans” and the “ViewController” classes.
Ans (The background works are supposed to happen in this file. In the comments, I've mentioned what I want to do but unable to do. For example, I want to set the Label text from there but I can't. Since I have no idea how to do it I've just put a System.out.Println there. In the comments next to it, I've mentioned what I actually want to do.)
package com.dan.ans;
import com.dan.qn.Qn;
import com.dan.view.ViewController;
public class Ans {
public static void checkAns() {
// Checks if the ans is correct.
if (ViewController.getTextFieldInput().equalsIgnoreCase(Qn.getAns())) {
System.out.println("Correct!"); // Here I want the label to say 'Correct!' rather than it be print out in the console.
Qn.setQuestion(); // This gets the next question from the database. But again, I don't know how to make the changes show on the screen. (In the actual code I'd have a separate Label for each of these things)
} else { // Runs if it's not correct.
System.out.println("Incorrect!"); // Here I want the label to say 'Incorrect' rather than it be print out in the console.
}
}
}
ViewController
package com.dan.view;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import com.dan.ans.Ans;
import com.dan.qn.Qn;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
public class ViewController implements Initializable {
private static String textFieldInput; // I don't know how to access the typed info in the textField from another class. So I store it here and get it from it.
// This is the getter I use for it. (See above)
public static String getTextFieldInput() {
return textFieldInput;
}
#FXML
private Label label;
#FXML
private TextField textField;
#Override
public void initialize(URL location, ResourceBundle resources) {
Qn.setQuestion(); // This method is in the Qn class. It retrieves data from the db file and keeps them in variables.
label.setText(Qn.getQn()); // This sets the label's text using the retrieved data. So you see the first question when the program opens.
}
// Event Listener on TextField[#textField].onAction
public void enter(ActionEvent event) throws IOException {
textFieldInput = textField.getText(); // Stores the typed info in the variable to be accessed from elsewhere.
Ans.checkAns(); // Runs the checkAns to check if the typed answer is correct or not.
}
}
The “Launcher” method just looks like any method with a main class. So I haven’t shared its code here.
Could someone please show me how I can update the components in the GUI from other classes such as “Ans”? I’m pretty sure I should use Platform.runLater() and Runnable. Also may be Tasks. I’ve seen several examples but it’s not clear how I can use it this context.
Thanks a lot in advance! :)
It's not really particularly clear what the issue is here. The natural (to me, anyway) approach would simply be to make the checkAnswer(...) method a method that simply "does what it says on the box", i.e. that takes an answer as a parameter, checks it, and returns a value to the caller indicating if it is correct.
That way you can also avoid all the ugly static hacks.
public class Ans {
public boolean checkAns(String answer) {
// not really sure what Qn is here, but you can also clean this up and
// get rid of the static methods
if (answer.equalsIgnoreCase(Qn.getAns()) {
// not sure if this really belongs here?
Qn.setQuestion(); // really takes no parameters? Sets it to what, then?
return true ;
} else {
return false ;
}
}
}
And then in your controller, you can just do
public class ViewController implements Initializable {
private Ans ans ;
#FXML
private Label label;
#FXML
private TextField textField;
#Override
public void initialize(URL location, ResourceBundle resources) {
ans = new Ans();
// ...
}
// ...
public void enter(ActionEvent event) {
if (ans.checkAns(textField.getText())) {
// update UI to show answer was correct, etc
} else {
// update UI to show answer was incorrect...
}
}
// ...
}
Note how this allows you to maintain proper separation of concerns: the Ans class doesn't need to know anything at all about the UI (which it should not know about at all), and all the UI-specific code is encapsulated in the controller class where it belongs.
It's not really clear why you are asking about Platform.runLater(...) and using Task, since none of the code you posted appears to involve any background threads (i.e. none of this code seems to take an appreciable amount of time to run). If, for example, the checkAns(...) method was doing some remote lookup and did take time to run, you would execute it in a Task and update the UI from the task's onSucceeded handler. See, e.g. Using threads to make database requests. Your question really seems to be more about basic OO design and how to define the relationships between different objects, though; I don't think you are actually asking about threading at all.
<a id="ctl00_cphBody_gvMessageList_ctl02_hlnkMessageSubject" href="Message.aspx?id=3428&member=">DDM IT QUIZ 2017 – Bhubaneswar Edition</a>
<a id="ctl00_cphBody_gvMessageList_ctl03_hlnkMessageSubject" href="Message.aspx?id=3427&member=">[Paybooks] Tax/investment declaration proof FY 2016-17</a>
<a id="ctl00_cphBody_gvMessageList_ctl04_hlnkMessageSubject" href="Message.aspx?id=3426&member=">Reimbursement clarification</a>
out:
DDM IT QUIZ 2017 – Bhubaneswar Edition
[Paybooks] Tax/investment declaration proof FY 2016-17
Reimbursement clarification
How can i get the relative xpaths for these three elements, so that I can get the above mentioned texts.
xpath = '//a/text()'
This will return a list of text
A complete answer would be:
to get all a elements of the same type, in this case having an id with ctl00
//a[contains(#id, 'ctl00')]
you can add more restriction, for example add a href restriction, to contain a certain string in his value
//a[contains(#id, 'ctl00')][contains(#href, 'Message')]
to get all a element is enough to just use
//a
In order to get text, you can use a method to get the text from your framework or add /text() to your xpath expression.
You can use the span class [relative xpath] like the following example along with the mouse operations and keyboard operations.
Check this out and let me know!
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;
public class SnapD {
public static void main(String args[]){
WebDriver d=new FirefoxDriver();
d.get("https://www.snapdeal.com/");
d.manage().window().maximize();
d.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
System.out.println("Hello Google...");
System.out.println("Hello Snapdeal...");
WebElement wb= d.findElement(By.xpath("//span[text()='Electronics']"));
Actions act=new Actions(d);
act.moveToElement(wb);
act.perform();
System.out.println("Mouse hovered");
WebElement wb1=d.findElement(By.xpath("//span[text()='DTH Services']"));
act.contextClick(wb1).perform();
act.sendKeys(Keys.ARROW_DOWN,Keys.ENTER).perform();
act.sendKeys(Keys.chord(Keys.CONTROL,Keys.TAB)).perform();
}
}