J'ai le code suivant:
public class NewClass {
public String noTags(String str){
return Jsoup.parse(str).text();
}
public static void main(String args[]) {
String strings="<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN \">" +
"<HTML> <HEAD> <TITLE></TITLE> <style>body{ font-size: 12px;font-family: verdana, arial, helvetica, sans-serif;}</style> </HEAD> <BODY><p><b>hello world</b></p><p><br><b>yo</b> <a href=\"http://google.com\">googlez</a></p></BODY> </HTML> ";
NewClass text = new NewClass();
System.out.println((text.noTags(strings)));
}
Et j'ai le résultat:
hello world yo googlez
Mais je veux rompre la ligne:
hello world
yo googlez
J'ai regardé (TextNode de jsoup # getWholeText () mais je ne peux pas comprendre comment l'utiliser.
S'il y a un <br>
dans le balisage que j'analyse, comment puis-je obtenir un saut de ligne dans la sortie résultante?
La vraie solution qui préserve les sauts de ligne devrait être la suivante:
public static String br2nl(String html) {
if(html==null)
return html;
Document document = Jsoup.parse(html);
document.outputSettings(new Document.OutputSettings().prettyPrint(false));//makes html() preserve linebreaks and spacing
document.select("br").append("\\n");
document.select("p").prepend("\\n\\n");
String s = document.html().replaceAll("\\\\n", "\n");
return Jsoup.clean(s, "", Whitelist.none(), new Document.OutputSettings().prettyPrint(false));
}
Il répond aux exigences suivantes:
Avec
Jsoup.parse("A\nB").text();
vous avez une sortie
"A B"
et pas
A
B
Pour cela j'utilise:
descrizione = Jsoup.parse(html.replaceAll("(?i)<br[^>]*>", "br2n")).text();
text = descrizione.replaceAll("br2n", "\n");
Jsoup.clean(unsafeString, "", Whitelist.none(), new OutputSettings().prettyPrint(false));
Nous utilisons cette méthode ici:
public static String clean(String bodyHtml,
String baseUri,
Whitelist whitelist,
Document.OutputSettings outputSettings)
En le passant Whitelist.none()
, nous nous assurons que tout le HTML est supprimé.
En transmettant new OutputSettings().prettyPrint(false)
, nous nous assurons que la sortie n'est pas reformatée et que les sauts de ligne sont préservés.
Essayez ceci en utilisant jsoup:
public static String cleanPreserveLineBreaks(String bodyHtml) {
// get pretty printed html with preserved br and p tags
String prettyPrintedBodyFragment = Jsoup.clean(bodyHtml, "", Whitelist.none().addTags("br", "p"), new OutputSettings().prettyPrint(true));
// get plain text with preserved line breaks by disabled prettyPrint
return Jsoup.clean(prettyPrintedBodyFragment, "", Whitelist.none(), new OutputSettings().prettyPrint(false));
}
Sur Jsoup v1.11.2, nous pouvons maintenant utiliser Element.wholeText()
.
Exemple de code:
String cleanString = Jsoup.parse(htmlString).wholeText();
user121196's
réponse fonctionne toujours. Mais wholeText()
préserve l'alignement des textes.
Vous pouvez traverser un élément donné
public String convertNodeToText(Element element)
{
final StringBuilder buffer = new StringBuilder();
new NodeTraversor(new NodeVisitor() {
boolean isNewline = true;
@Override
public void head(Node node, int depth) {
if (node instanceof TextNode) {
TextNode textNode = (TextNode) node;
String text = textNode.text().replace('\u00A0', ' ').trim();
if(!text.isEmpty())
{
buffer.append(text);
isNewline = false;
}
} else if (node instanceof Element) {
Element element = (Element) node;
if (!isNewline)
{
if((element.isBlock() || element.tagName().equals("br")))
{
buffer.append("\n");
isNewline = true;
}
}
}
}
@Override
public void tail(Node node, int depth) {
}
}).traverse(element);
return buffer.toString();
}
Et pour votre code
String result = convertNodeToText(JSoup.parse(html))
text = Jsoup.parse(html.replaceAll("(?i)<br[^>]*>", "br2n")).text();
text = descrizione.replaceAll("br2n", "\n");
fonctionne si le code HTML lui-même ne contient pas "br2n"
Alors,
text = Jsoup.parse(html.replaceAll("(?i)<br[^>]*>", "<pre>\n</pre>")).text();
fonctionne plus fiable et plus facile.
Sur la base des autres réponses et des commentaires sur cette question, il semble que la plupart des gens qui viennent ici cherchent vraiment une solution générale qui fournira une représentation au format texte clair et bien formatée d’un document HTML. Je sais que j'étais.
Heureusement, JSoup fournit déjà un exemple assez complet expliquant comment y parvenir: HtmlToPlainText.Java
L'exemple FormattingVisitor
peut facilement être modifié selon vos préférences et traite de la plupart des éléments de bloc et du retour à la ligne.
Pour éviter la pourriture de lien, voici la solution de Jonathan Hedley :
package org.jsoup.examples;
import org.jsoup.Jsoup;
import org.jsoup.helper.StringUtil;
import org.jsoup.helper.Validate;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.Elements;
import org.jsoup.select.NodeTraversor;
import org.jsoup.select.NodeVisitor;
import Java.io.IOException;
/**
* HTML to plain-text. This example program demonstrates the use of jsoup to convert HTML input to lightly-formatted
* plain-text. That is divergent from the general goal of jsoup's .text() methods, which is to get clean data from a
* scrape.
* <p>
* Note that this is a fairly simplistic formatter -- for real world use you'll want to embrace and extend.
* </p>
* <p>
* To invoke from the command line, assuming you've downloaded the jsoup jar to your current directory:</p>
* <p><code>Java -cp jsoup.jar org.jsoup.examples.HtmlToPlainText url [selector]</code></p>
* where <i>url</i> is the URL to fetch, and <i>selector</i> is an optional CSS selector.
*
* @author Jonathan Hedley, [email protected]
*/
public class HtmlToPlainText {
private static final String userAgent = "Mozilla/5.0 (jsoup)";
private static final int timeout = 5 * 1000;
public static void main(String... args) throws IOException {
Validate.isTrue(args.length == 1 || args.length == 2, "usage: Java -cp jsoup.jar org.jsoup.examples.HtmlToPlainText url [selector]");
final String url = args[0];
final String selector = args.length == 2 ? args[1] : null;
// fetch the specified URL and parse to a HTML DOM
Document doc = Jsoup.connect(url).userAgent(userAgent).timeout(timeout).get();
HtmlToPlainText formatter = new HtmlToPlainText();
if (selector != null) {
Elements elements = doc.select(selector); // get each element that matches the CSS selector
for (Element element : elements) {
String plainText = formatter.getPlainText(element); // format that element to plain text
System.out.println(plainText);
}
} else { // format the whole doc
String plainText = formatter.getPlainText(doc);
System.out.println(plainText);
}
}
/**
* Format an Element to plain-text
* @param element the root element to format
* @return formatted text
*/
public String getPlainText(Element element) {
FormattingVisitor formatter = new FormattingVisitor();
NodeTraversor traversor = new NodeTraversor(formatter);
traversor.traverse(element); // walk the DOM, and call .head() and .tail() for each node
return formatter.toString();
}
// the formatting rules, implemented in a breadth-first DOM traverse
private class FormattingVisitor implements NodeVisitor {
private static final int maxWidth = 80;
private int width = 0;
private StringBuilder accum = new StringBuilder(); // holds the accumulated text
// hit when the node is first seen
public void head(Node node, int depth) {
String name = node.nodeName();
if (node instanceof TextNode)
append(((TextNode) node).text()); // TextNodes carry all user-readable text in the DOM.
else if (name.equals("li"))
append("\n * ");
else if (name.equals("dt"))
append(" ");
else if (StringUtil.in(name, "p", "h1", "h2", "h3", "h4", "h5", "tr"))
append("\n");
}
// hit when all of the node's children (if any) have been visited
public void tail(Node node, int depth) {
String name = node.nodeName();
if (StringUtil.in(name, "br", "dd", "dt", "p", "h1", "h2", "h3", "h4", "h5"))
append("\n");
else if (name.equals("a"))
append(String.format(" <%s>", node.absUrl("href")));
}
// appends text to the string builder with a simple Word wrap method
private void append(String text) {
if (text.startsWith("\n"))
width = 0; // reset counter if starts with a newline. only from formats above, not in natural text
if (text.equals(" ") &&
(accum.length() == 0 || StringUtil.in(accum.substring(accum.length() - 1), " ", "\n")))
return; // don't accumulate long runs of empty spaces
if (text.length() + width > maxWidth) { // won't fit, needs to wrap
String words[] = text.split("\\s+");
for (int i = 0; i < words.length; i++) {
String Word = words[i];
boolean last = i == words.length - 1;
if (!last) // insert a space if not the last Word
Word = Word + " ";
if (Word.length() + width > maxWidth) { // wrap and reset counter
accum.append("\n").append(Word);
width = Word.length();
} else {
accum.append(Word);
width += Word.length();
}
}
} else { // fits as is, without need to wrap text
accum.append(text);
width += text.length();
}
}
@Override
public String toString() {
return accum.toString();
}
}
}
Pour un code HTML plus complexe, aucune des solutions ci-dessus ne fonctionne parfaitement; J'ai pu réussir la conversion tout en préservant les sauts de ligne avec:
Document document = Jsoup.parse(myHtml);
String text = new HtmlToPlainText().getPlainText(document);
(version 1.10.3)
Ceci est ma version de la traduction de HTML en texte (la version modifiée de la réponse user121196, en fait).
Cela ne préserve pas seulement les sauts de ligne, mais aussi le formatage du texte et la suppression des sauts de ligne excessifs, des symboles d'échappement HTML, et vous obtiendrez un bien meilleur résultat de votre code HTML (dans mon cas, je le reçois par courrier).
Il est écrit à l’origine en Scala, mais vous pouvez le remplacer par Java facilement
def html2text( rawHtml : String ) : String = {
val htmlDoc = Jsoup.parseBodyFragment( rawHtml, "/" )
htmlDoc.select("br").append("\\nl")
htmlDoc.select("div").prepend("\\nl").append("\\nl")
htmlDoc.select("p").prepend("\\nl\\nl").append("\\nl\\nl")
org.jsoup.parser.Parser.unescapeEntities(
Jsoup.clean(
htmlDoc.html(),
"",
Whitelist.none(),
new org.jsoup.nodes.Document.OutputSettings().prettyPrint(true)
),false
).
replaceAll("\\\\nl", "\n").
replaceAll("\r","").
replaceAll("\n\\s+\n","\n").
replaceAll("\n\n+","\n\n").
trim()
}
Essayez ceci en utilisant jsoup:
doc.outputSettings(new OutputSettings().prettyPrint(false));
//select all <br> tags and append \n after that
doc.select("br").after("\\n");
//select all <p> tags and prepend \n before that
doc.select("p").before("\\n");
//get the HTML from the document, and retaining original new lines
String str = doc.html().replaceAll("\\\\n", "\n");
Essaye ça:
public String noTags(String str){
Document d = Jsoup.parse(str);
TextNode tn = new TextNode(d.body().html(), "");
return tn.getWholeText();
}
Utilisez textNodes()
pour obtenir une liste des nœuds de texte. Puis concaténez-les avec \n
comme séparateur. Voici quelques scala le code que j'utilise pour cela, Java devrait être simple:
val rawTxt = doc.body().getElementsByTag("div").first.textNodes()
.asScala.mkString("<br />\n")
Basé sur la réponse de user121196 et de Green Beret avec select
s et <pre>
s, la seule solution qui fonctionne pour moi est la suivante:
org.jsoup.nodes.Element elementWithHtml = ....
elementWithHtml.select("br").append("<pre>\n</pre>");
elementWithHtml.select("p").prepend("<pre>\n\n</pre>");
elementWithHtml.text();
/**
* Recursive method to replace html br with Java \n. The recursive method ensures that the linebreaker can never end up pre-existing in the text being replaced.
* @param html
* @param linebreakerString
* @return the html as String with proper Java newlines instead of br
*/
public static String replaceBrWithNewLine(String html, String linebreakerString){
String result = "";
if(html.contains(linebreakerString)){
result = replaceBrWithNewLine(html, linebreakerString+"1");
} else {
result = Jsoup.parse(html.replaceAll("(?i)<br[^>]*>", linebreakerString)).text(); // replace and html line breaks with Java linebreak.
result = result.replaceAll(linebreakerString, "\n");
}
return result;
}
Utilisé en appelant avec le code HTML en question, contenant le br, ainsi que la chaîne que vous souhaitez utiliser comme espace réservé de nouvelle ligne temporaire. Par exemple:
replaceBrWithNewLine(element.html(), "br2n")
La récursion veillera à ce que la chaîne que vous utilisez en tant qu'espace réservé newline/linebreaker ne soit jamais réellement dans le code HTML source, car il continue d'ajouter un "1" jusqu'à ce que la chaîne d'espace réservé pour le séparateur de liens ne soit pas trouvée dans le code HTML. Il n’aura pas le problème de formatage que les méthodes Jsoup.clean semblent rencontrer avec des caractères spéciaux.