本文目录导读:

针对 JEditorPane、HTMLEditorKit 和 HTML 解析输出的处理,这里整理了一份完整指南,涵盖常见场景和解决方案。
基础架构理解
JEditorPane
└── EditorKit (HTMLEditorKit)
└── Parser (默认是 javax.swing.text.html.parser.ParserDelegator)
└── Callback (HTMLEditorKit.ParserCallback)
└── 输出:各种 handleXxx 方法
核心处理方式
1 使用 ParserCallback 解析HTML
HTMLEditorKit.Parser parser = new HTMLEditorKit().getParser();
String html = "<html><body><h1>Title</h1><p>Content</p></body></html>";
Reader reader = new StringReader(html);
parser.parse(reader, new HTMLEditorKit.ParserCallback() {
@Override
public void handleText(char[] data, int pos) {
System.out.println("Text: " + new String(data));
}
@Override
public void handleStartTag(HTML.Tag tag, MutableAttributeSet attributes, int pos) {
System.out.println("Start Tag: " + tag + ", attrs: " + attributes);
}
@Override
public void handleEndTag(HTML.Tag tag, int pos) {
System.out.println("End Tag: " + tag);
}
@Override
public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attributes, int pos) {
System.out.println("Simple Tag: " + tag + ", attrs: " + attributes);
}
@Override
public void handleError(String errorMsg, int pos) {
System.err.println("Error at " + pos + ": " + errorMsg);
}
}, true); // true = ignore charset
2 提取纯文本内容
public String extractPlainText(String html) {
StringBuilder sb = new StringBuilder();
try {
HTMLEditorKit.Parser parser = new HTMLEditorKit().getParser();
Reader reader = new StringReader(html);
parser.parse(reader, new HTMLEditorKit.ParserCallback() {
@Override
public void handleText(char[] data, int pos) {
sb.append(data);
}
@Override
public void handleEndTag(HTML.Tag tag, int pos) {
if (tag == HTML.Tag.BR || tag == HTML.Tag.P || tag == HTML.Tag.DIV) {
sb.append("\n");
}
}
}, true);
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString().trim();
}
保存和恢复 HTML 内容
1 从 JEditorPane 获取 HTML
public String getHTMLContent(JEditorPane editorPane) {
// 方法1: 使用 Document 输出
StringWriter writer = new StringWriter();
try {
editorPane.getEditorKit().write(writer, editorPane.getDocument(), 0,
editorPane.getDocument().getLength());
return writer.toString();
} catch (IOException | BadLocationException e) {
e.printStackTrace();
}
return null;
// 方法2: 直接读取HTML
// return editorPane.getText(); // 获取纯文本
}
2 设置 HTML 内容
public void setHTMLContent(JEditorPane editorPane, String html) {
editorPane.setContentType("text/html");
editorPane.setText(html);
// 或者通过 Document
// try {
// editorPane.getEditorKit().read(
// new StringReader(html),
// editorPane.getDocument(),
// 0
// );
// } catch (Exception e) {
// e.printStackTrace();
// }
}
自定义解析器输出处理器
1 带状态追踪的解析器
public class AdvancedHTMLParser extends HTMLEditorKit.ParserCallback {
private final StringBuilder output = new StringBuilder();
private final Stack<HTML.Tag> tagStack = new Stack<>();
private boolean inScript = false;
private boolean inStyle = false;
@Override
public void handleStartTag(HTML.Tag tag, MutableAttributeSet attrs, int pos) {
tagStack.push(tag);
if (tag == HTML.Tag.SCRIPT) inScript = true;
if (tag == HTML.Tag.STYLE) inStyle = true;
// 自定义输出格式
if (!inScript && !inStyle) {
output.append("<").append(tag);
// 处理属性
Enumeration<?> names = attrs.getAttributeNames();
while (names.hasMoreElements()) {
Object name = names.nextElement();
output.append(" ").append(name)
.append("=\"").append(attrs.getAttribute(name)).append("\"");
}
output.append(">\n");
}
}
@Override
public void handleEndTag(HTML.Tag tag, int pos) {
if (tag == HTML.Tag.SCRIPT) inScript = false;
if (tag == HTML.Tag.STYLE) inStyle = false;
if (!tagStack.isEmpty()) {
tagStack.pop();
}
if (!inScript && !inStyle) {
output.append("</").append(tag).append(">\n");
}
}
@Override
public void handleText(char[] data, int pos) {
if (!inScript && !inStyle) {
output.append(new String(data)).append("\n");
}
}
public String getProcessedOutput() {
return output.toString();
}
}
2 统计信息收集器
public class HTMLStatisticsCollector extends HTMLEditorKit.ParserCallback {
private final Map<HTML.Tag, Integer> tagCount = new HashMap<>();
private int totalTextLength = 0;
private int linkCount = 0;
private int imageCount = 0;
@Override
public void handleStartTag(HTML.Tag tag, MutableAttributeSet attrs, int pos) {
tagCount.merge(tag, 1, Integer::sum);
if (tag == HTML.Tag.A) linkCount++;
if (tag == HTML.Tag.IMG) imageCount++;
// 收集特定属性
if (tag == HTML.Tag.A) {
String href = (String) attrs.getAttribute(HTML.Attribute.HREF);
if (href != null) {
System.out.println("Link found: " + href);
}
}
}
@Override
public void handleText(char[] data, int pos) {
totalTextLength += new String(data).trim().length();
}
public void printStatistics() {
System.out.println("=== HTML Statistics ===");
System.out.println("Total tags: " + tagCount.values().stream().mapToInt(Integer::intValue).sum());
System.out.println("Total text length: " + totalTextLength);
System.out.println("Links: " + linkCount);
System.out.println("Images: " + imageCount);
System.out.println("\nTag breakdown:");
tagCount.entrySet().stream()
.sorted(Map.Entry.<HTML.Tag, Integer>comparingByValue().reversed())
.forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));
}
}
实际应用示例
1 完整的HTML编辑器
import javax.swing.*;
import javax.swing.text.html.*;
import java.awt.*;
public class HTMLEditorExample {
private JEditorPane editor;
public void createAndShowGUI() {
JFrame frame = new JFrame("HTML Editor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 400);
editor = new JEditorPane();
editor.setContentType("text/html");
editor.setEditable(true);
editor.setText("<html><body><h1>Hello World</h1></body></html>");
// 添加按钮
JButton parseBtn = new JButton("Parse and Analyze");
parseBtn.addActionListener(e -> parseAndAnalyze());
JButton extractTextBtn = new JButton("Extract Text");
extractTextBtn.addActionListener(e -> extractText());
JPanel buttonPanel = new JPanel();
buttonPanel.add(parseBtn);
buttonPanel.add(extractTextBtn);
frame.add(new JScrollPane(editor), BorderLayout.CENTER);
frame.add(buttonPanel, BorderLayout.SOUTH);
frame.setVisible(true);
}
private void parseAndAnalyze() {
String htmlContent = getHTMLContent();
if (htmlContent != null) {
HTMLStatisticsCollector collector = new HTMLStatisticsCollector();
try {
HTMLEditorKit.Parser parser = new HTMLEditorKit().getParser();
parser.parse(new StringReader(htmlContent), collector, true);
collector.printStatistics();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
private void extractText() {
String htmlContent = getHTMLContent();
if (htmlContent != null) {
String plainText = extractPlainText(htmlContent);
JOptionPane.showMessageDialog(editor, plainText, "Extracted Text",
JOptionPane.INFORMATION_MESSAGE);
}
}
private String getHTMLContent() {
StringWriter writer = new StringWriter();
try {
editor.getEditorKit().write(writer, editor.getDocument(), 0,
editor.getDocument().getLength());
return writer.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new HTMLEditorExample().createAndShowGUI());
}
}
2 自定义渲染输出
public class CustomHTMLRenderer {
public static String renderToCustomFormat(String html) {
StringBuilder sb = new StringBuilder();
try {
HTMLEditorKit.Parser parser = new HTMLEditorKit().getParser();
parser.parse(new StringReader(html), new HTMLEditorKit.ParserCallback() {
int indent = 0;
@Override
public void handleStartTag(HTML.Tag tag, MutableAttributeSet attrs, int pos) {
sb.append(" ".repeat(indent))
.append("[OPEN: ").append(tag);
if (attrs.getAttributeCount() > 0) {
sb.append(" attributes: ");
Enumeration<?> names = attrs.getAttributeNames();
while (names.hasMoreElements()) {
Object name = names.nextElement();
sb.append(name).append("=").append(attrs.getAttribute(name));
if (names.hasMoreElements()) sb.append(", ");
}
}
sb.append("]\n");
indent++;
}
@Override
public void handleEndTag(HTML.Tag tag, int pos) {
indent--;
sb.append(" ".repeat(indent))
.append("[CLOSE: ").append(tag).append("]\n");
}
@Override
public void handleText(char[] data, int pos) {
String text = new String(data).trim();
if (!text.isEmpty()) {
sb.append(" ".repeat(indent))
.append("TEXT: \"").append(text).append("\"\n");
}
}
}, true);
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
}
常见问题与解决方案
1 中文乱码处理
// 设置正确的字符编码
HTMLEditorKit kit = new HTMLEditorKit();
kit.setDefaultCharset("UTF-8");
editorPane.setEditorKit(kit);
// 或者在解析时指定
parser.parse(new InputStreamReader(inputStream, "UTF-8"), callback, false);
2 处理不完整/错误HTML
// 使用更宽容的解析器 HTMLDocument doc = (HTMLDocument) editorPane.getDocument(); doc.setAsynchronousLoadPriority(-1); // 同步加载 doc.setPreservesUnknownTags(true); // 保留未知标签
3 性能优化
// 批量处理文档更新
editorPane.getDocument().addDocumentListener(new DocumentListener() {
private final Timer timer = new Timer(300, e -> processChanges());
@Override
public void insertUpdate(DocumentEvent e) {
timer.restart(); // 延迟300ms处理
}
@Override
public void removeUpdate(DocumentEvent e) {
timer.restart();
}
@Override
public void changedUpdate(DocumentEvent e) {
timer.restart();
}
private void processChanges() {
// 这里执行实际的解析和输出处理
}
});
最佳实践
- 始终在EDT线程中处理UI相关操作
- 对大文档使用异步解析
- 关闭自动加载图片:
editorPane.setAutoscrolls(false) - 使用HTMLDocument而不是直接操作文本
- 考虑使用第三方库(如jsoup)处理复杂HTML
这套方案涵盖了从基础解析到高级处理的各种场景,可以根据具体需求选择合适的实现方式。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播