Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent Jsoup from discarding extra whitespace

Tags:

java

jsoup

I'm using Jsoup for sanitizing user input from a form. The form in question contains a <textarea> that expects plain text. When the form is submitted, I clean the input with Jsoup.clean(textareaContents); however, since html ignores extra whitespace, Jsoup.clean() will remove valuable whitespace characters from the input.

For example, if someone entered some lines of text in the textarea:

hello

test

after Jsoup.clean(), you will have:

hello test

How can you make Jsoup.clean() preserve whitespace? I know it's designed for parsing html and this isn't html, so is there a better alternative?

like image 948
Keith Avatar asked Mar 28 '11 02:03

Keith


3 Answers

For future generations, if you still need to get access to original text with whitespace, you can use TextNode.getWholeText() method.

Sample code:

/**
 * @param cell element that contains whitespace formatting
 * @return
 */
public static String getText(Element cell) {
    String text = null;
    List<Node> childNodes = cell.childNodes();
    if (childNodes.size() > 0) {
        Node childNode = childNodes.get(0);
        if (childNode instanceof TextNode) {
            text = ((TextNode)childNode).getWholeText();
        }
    }
    if (text == null) {
        text = cell.text();
    }
    return text;
}

In the code above, we assume that the passed in element contains text content directly inside element body (we take the first node). If that is not so, it will fall back to regular Element.text() method.

like image 140
Neeme Praks Avatar answered Oct 24 '22 04:10

Neeme Praks


If your textarea just expects plain text, then I think you'd be better off just HTML escaping the plain text. I.e. convert user's input < and > tags to &lt; and &gt; respectively. Either on input our output (input might be safer so you only need to think about it once).

The jsoup HTML cleaner is, as you say, designed to parse untrusted input HTML and outuput trusted HTML, where formatting is done with elements.

like image 39
Jonathan Hedley Avatar answered Oct 24 '22 04:10

Jonathan Hedley


Neeme Praks' answer was very good and preserved whitespace correctly. However, inline HTML really messes it up.

<span>This is<br />some text.  Cool story.</span>

Results in

"This is"

Or if you pass in an element that doesn't have its own text, it returns null.

So I had to rework the method a little for my purposes. This might help some folks so I'm posting it here. The basic idea is to iterate the children instead of just taking the first one. This also includes a case to grab the HTML for any elements without children.

This way the original snippet returns:

This is<br />some text.  Cool story.

public static String getText(Element cell) {
    StringBuilder textBuilder = new StringBuilder();
    for (Node node : cell.childNodes()) {
        if (node instanceof TextNode) {
            textBuilder.append(((TextNode)node).getWholeText());
        }
        else {
            for (Node childNode : node.childNodes()) {
                textBuilder.append(getText((Element)childNode));
            }
            textBuilder.append(node.outerHtml());
        }
    }
    if (cell.childNodes().isEmpty()) {
        textBuilder.append(cell.outerHtml());
    }
    return textBuilder.toString();
}
like image 36
Sloloem Avatar answered Oct 24 '22 05:10

Sloloem