为了支持全文检索,有必要将HTML格式的文章转化为纯文本格式,因此我设计了一个基本的WebFormatter类,提供一个简单的public static String html2text(String html),将HTML格式转化为Text:
/*
* File: WebFormatter.java
* Created on 2005-6-24
* Author: Liao Xuefeng, asklxf@163.com
* Copyright (C) 2005, Liao Xuefeng.
*/
package com.mboker.blog.web.util;
import java.util.*;
import java.text.SimpleDateFormat;
/**
* Do some format on web display.
*
* @author Xuefeng
*/
public class WebFormatter {
public static String html2text(String html) {
StringBuffer sb = new StringBuffer(html.length());
char[] data = html.toCharArray();
int start = 0;
boolean previousIsPre = false;
Token token = null;
for(;;) {
token = parse(data, start, previousIsPre);
if(token==null)
break;
previousIsPre = token.isPreTag();
sb = sb.append(token.getText());
start += token.getLength();
}
return sb.toString();
}
private static Token parse(char[] data, int start, boolean previousIsPre) {
if(start>=data.length)
return null;
// try to read next char:
char c = data[start];
if(c=='<') {
// this is a tag or comment or script:
int end_index = indexOf(data, start+1, '>');
if(end_index==(-1)) {
// the left is all text!
return new Token(Token.TOKEN_TEXT, data, start, data.length, previousIsPre);
}
String s = new String(data, start, end_index-start+1);
// now we got s="<...>":
if(s.startsWith("<!--")) { // this is a comment!
int end_comment_index = indexOf(data, start+1, "-->");
if(end_comment_index==(-1)) {
// illegal end, but treat as comment:
return new Token(Token.TOKEN_COMMENT, data, start, data.length, previousIsPre);
}
else
return new Token(Token.TOKEN_COMMENT, data, start, end_comment_index+3, previousIsPre);
}
String s_lowerCase = s.toLowerCase();
if(s_lowerCase.startsWith("<script")) { // this is a script:
int end_script_index = indexOf(data, start+1, "</script>");
if(end_script_index==(-1))
// illegal end, but treat as script:
return new Token(Token.TOKEN_SCRIPT, data, start, data.length, previousIsPre);
else
return new Token(Token.TOKEN_SCRIPT, data, start, end_script_index+9, previousIsPre);
}
else { // this is a tag:
return new Token(Token.TOKEN_TAG, data, start, start+s.length(), previousIsPre);
}
}
// this is a text:
int next_tag_index = indexOf(data, start+1, '<');
if(next_tag_index==(-1))
return new Token(Token.TOKEN_TEXT, data, start, data.length, previousIsPre);
return new Token(Token.TOKEN_TEXT, data, start, next_tag_index, previousIsPre);
}
private static int indexOf(char[] data, int start, String s) {
char[] ss = s.toCharArray();
// TODO: performance can improve!
for(int i=start; i<(data.length-ss.length); i++) {
// compare from data[i] with ss[0]:
boolean match = true;
for(int j=0; j<ss.length; j++) {
if(data[i+j]!=ss[j]) {
match = false;
break;
}
}
if(match)
return i;
}
return (-1);
}
private static int indexOf(char[] data, int start, char c) {
for(int i=start; i<data.length; i++) {
if(data[i]==c)
return i;
}
return (-1);
}
}
class Token {
public static final int TOKEN_TEXT = 0; // html text.
public static final int TOKEN_COMMENT = 1; // comment like <!-- comments... -->
public static final int TOKEN_TAG = 2; // tag like <pre>, <font>, etc.
public static final int TOKEN_SCRIPT = 3;
private static final char[] TAG_BR = "<br".toCharArray();
private static final char[] TAG_P = "<p".toCharArray();
private static final char[] TAG_LI = "<li".toCharArray();
private static final char[] TAG_PRE = "<pre".toCharArray();
private static final char[] TAG_HR = "<hr".toCharArray();
private static final char[] END_TAG_TD = "</td>".toCharArray();
private static final char[] END_TAG_TR = "</tr>".toCharArray();
private static final char[] END_TAG_LI = "</li>".toCharArray();
private static final Map SPECIAL_CHARS = new HashMap();
private int type;
private String html; // original html
private String text = null; // text!
private int length = 0; // html length
private boolean isPre = false; // isPre tag?
static {
SPECIAL_CHARS.put(""", "\"");
SPECIAL_CHARS.put("<", "<");
SPECIAL_CHARS.put(">", ">");
SPECIAL_CHARS.put("&", "&");
SPECIAL_CHARS.put("®", "(r)");
SPECIAL_CHARS.put("©", "(c)");
SPECIAL_CHARS.put(" ", " ");
SPECIAL_CHARS.put("£", "?");
}
public Token(int type, char[] data, int start, int end, boolean previousIsPre) {
this.type = type;
this.length = end - start;
this.html = new String(data, start, length);
System.out.println("[Token] html=" + html + ".");
parseText(previousIsPre);
System.out.println("[Token] text=" + text + ".");
}
public int getLength() {
return length;
}
public boolean isPreTag() {
return isPre;
}
private void parseText(boolean previousIsPre) {
if(type==TOKEN_TAG) {
char[] cs = html.toCharArray();
if(compareTag(TAG_BR, cs) || compareTag(TAG_P, cs))
text = "\n";
else if(compareTag(TAG_LI, cs))
text = "\n* ";
else if(compareTag(TAG_PRE, cs))
isPre = true;
else if(compareTag(TAG_HR, cs))
text = "\n--------\n";
else if(compareString(END_TAG_TD, cs))
text = "\t";
else if(compareString(END_TAG_TR, cs) || compareString(END_TAG_LI, cs))
text = "\n";
}
// text token:
else if(type==TOKEN_TEXT) {
text = toText(html, previousIsPre);
}
}
public String getText() {
return text==null ? "" : text;
}
private String toText(String html, final boolean isPre) {
char[] cs = html.toCharArray();
StringBuffer buffer = new StringBuffer(cs.length);
int start = 0;
boolean continueSpace = false;
char current, next;
for(;;) {
if(start>=cs.length)
break;
current = cs[start]; // read current char
if(start+1<cs.length) // and next char
next = cs[start+1];
else
next = '\0';
if(current==' ') {
if(isPre || !continueSpace)
buffer = buffer.append(' ');
continueSpace = true;
// continue loop:
start++;
continue;
}
// not ' ', so:
if(current=='\r' && next=='\n') {
if(isPre)
buffer = buffer.append('\n');
// continue loop:
start+=2;
continue;
}
if(current=='\n' || current=='\r') {
if(isPre)
buffer = buffer.append('\n');
// continue loop:
start++;
continue;
}
// cannot continue space:
continueSpace = false;
if(current=='&') {
// maybe special char:
int length = readUtil(cs, start, ';', 10);
if(length==(-1)) { // just '&':
buffer = buffer.append('&');
// continue loop:
start++;
continue;
}
else { // check if special character:
String spec = new String(cs, start, length);
String specChar = (String)SPECIAL_CHARS.get(spec);
if(specChar!=null) { // special chars!
buffer = buffer.append(specChar);
// continue loop:
start+=length;
continue;
}
else { // check if like 'Ӓ':
if(next=='#') { // maybe a char
String num = new String(cs, start+2, length-3);
try {
int code = Integer.parseInt(num);
if(code>0 && code<65536) { // this is a special char:
buffer = buffer.append((char)code);
// continue loop:
start++;
continue;
}
}
catch(Exception e) {}
// just normal char:
buffer = buffer.append("&#");
// continue loop:
start+=2;
continue;
}
else { // just '&':
buffer = buffer.append('&');
// continue loop:
start++;
continue;
}
}
}
}
else { // just a normal char!
buffer = buffer.append(current);
// continue loop:
start++;
continue;
}
}
return buffer.toString();
}
// read from cs[start] util meet the specified char 'util',
// or null if not found:
private int readUtil(final char[] cs, final int start, final char util, final int maxLength) {
int end = start+maxLength;
if(end>cs.length)
end = cs.length;
for(int i=start; i<start+maxLength; i++) {
if(cs[i]==util) {
return i-start+1;
}
}
return (-1);
}
// compare standard tag "<input" with tag "<INPUT value=aa>"
private boolean compareTag(final char[] ori_tag, char[] tag) {
if(ori_tag.length>=tag.length)
return false;
for(int i=0; i<ori_tag.length; i++) {
if(Character.toLowerCase(tag[i])!=ori_tag[i])
return false;
}
// the following char should not be a-z:
if(tag.length>ori_tag.length) {
char c = Character.toLowerCase(tag[ori_tag.length]);
if(c<'a' || c>'z')
return true;
return false;
}
return true;
}
private boolean compareString(final char[] ori, char[] comp) {
if(ori.length>comp.length)
return false;
for(int i=0; i<ori.length; i++) {
if(Character.toLowerCase(comp[i])!=ori[i])
return false;
}
return true;
}
public String toString() {
return html;
}
}
注意,请先将html中的<body>...</body>部分提取出来,再交给WebFormatter处理,因为html->text转换实质是删除所有标签(某些标签如<br>被转化为'\n')、Script和注释,对于JavaScript生成的动态内容(例如document.write)无能为力。
分享到:
相关推荐
Java转化成HTML涉及到的是将Java程序的输出或者数据转换成HTML格式,以便在Web浏览器中展示。而HTML转Java则可能指的是将HTML页面的内容提取出来,用Java进行处理或者解析。这两种转换在Web开发、数据迁移、爬虫等...
6. **工具与库**:有许多现成的工具和编程库可以方便地完成HTML到文本的转换,例如Python的`html2text`库,它能将HTML字符串转换为Markdown格式的文本,或者JavaScript的`html-text`库,同样实现了这个功能。...
在IT行业中,转换文档格式是常见的需求之一,例如将HTML转换为RTF,或者反过来将RTF转换为HTML,甚至将HTML转换为PDF。这些转换在处理文本内容、排版和样式时尤其有用,比如在网页与桌面应用程序之间进行数据交换,...
在Java编程中,将HTML字符串转换为纯文本字符串是一个常见的需求,这主要涉及到解析HTML文档并提取其中的文本内容。HTML是一种标记语言,用于构建网页结构,而纯文本则只包含可读字符,不含有任何格式化或结构信息。...
lang和lang3这两个包里有转换所需的工具类 org.jsoup jsoup 1.11.3 commons-lang commons-lang 2.6 org.apache.commons commons-lang3 3.4 第二步:直接使用即可: import org.apache.commons.lang....
总结,要实现在Java中将HTML转换为PDF并添加电子签章,可以利用`Flying Saucer`库将HTML渲染为PDF,再使用`iText`库在生成的PDF上插入印章图片。通过这种方式,可以创建具有合法性和安全性的电子文档,满足电子合同...
Java 使用 Jacob 库将 Office 文件转换为 HTML 是一个常见的需求,尤其在自动化处理文档或在线预览场景中。Jacob(Java and COM Bridge)是一个 Java 库,它允许 Java 应用程序通过 COM(Component Object Model)...
在Java开发中,有时我们需要将HTML内容转换成Word文档,以便于阅读、编辑或打印。这个过程涉及到HTML解析、格式转换以及可能的图像处理。在本文中,我们将深入探讨如何在Java中实现这一功能,以及需要用到的关键库和...
这段代码创建了一个HTTP GET请求,并读取了响应的输入流,将其转化为字符串。注意,实际应用中需要处理异常和关闭连接,以避免资源泄漏。 接下来,我们需要解析HTML文档。Java的标准库并没有提供HTML解析器,但我们...
javax.sound.sampled.spi 在提供新音频设备、声音文件 reader 和 writer,或音频格式转换器时,提供将为其创建子类的服务提供者的抽象类。 javax.sql 为通过 JavaTM 编程语言进行服务器端数据源访问和处理提供 API...
它能够将HTML字符串转换为一个可操作的Document对象,这个对象结构与原始HTML文档相匹配。例如: ```java import org.jsoup.Jsoup; import org.jsoup.nodes.Document; String html = "<html><head><title>Test...
</p></body></html>,然后使用Html2PlainText类将其转换为纯文本,结果将是:Hello World!\n这是一个测试文本。 本文介绍了一种使用Jsoup和commons-lang等库来将HTML格式文本转换为纯文本的方法。这种方法可以满足...
在IT行业中,将HTML转换为Word文档是一种常见的需求,特别是在数据导出、报告生成或网页内容保存时。Java作为一种强大的开发语言,提供了多种方法来实现这个功能。本篇将详细介绍如何利用Java技术栈,特别是Apache ...
在Java编程中,将文本内容中的符合URL格式的字符串转换为超链接是一项常见的需求,特别是在处理用户生成内容或网络爬虫应用中。本教程将详细讲解如何使用Java实现这一功能,主要涉及URL正则表达式匹配和字符串处理...
本篇文章将深入探讨如何使用Java将常见的办公文档,如Word、PPT、Excel和PDF,转换为HTML格式。这个过程通常涉及到读取源文件,解析其内容,并将其重新格式化为HTML的结构。 首先,让我们来理解为什么需要进行这种...
在版本2.0.8中,它提供了将HTML转换为PDF的功能,这对于从网页内容生成打印版或者提供离线阅读材料非常有用。这个过程涉及到多个步骤和技术,下面将详细阐述如何使用iText 2.0.8实现HTML到PDF的转换,并特别关注其中...
本篇文章将详细介绍如何在Java环境下将HTML转换为PDF,以及涉及的相关知识点。 首先,我们需要了解几个关键的概念和技术: 1. **HTML**: HyperText Markup Language,是用于创建网页的标准标记语言。它包含了文本...
`java.text`和`java.util.Locale`类支持多语言环境下的应用开发,提供日期、数字、货币格式化等功能。 9. **XML处理**: `javax.xml`包提供了处理XML文档的API,如`DocumentBuilderFactory`、`DocumentBuilder`...
本示例关注的是使用Java编程语言将传统的`.doc`格式文件转换为较新的`.docx`格式。`.doc`文件是Microsoft Word早期版本(Word 97到2003)使用的文件格式,而`.docx`则是从Word 2007开始引入的基于XML的格式。这种...