JEditorPaneHTMLEditorKitParserError错误处理

wen java案例 2

本文目录导读:

JEditorPaneHTMLEditorKitParserError错误处理

  1. 捕获并处理解析异常
  2. 自定义 HTMLEditorKit 的错误处理
  3. 预处理 HTML 以修复常见错误
  4. 使用更健壮的解析器(如 JSoup)预处理
  5. 设置全局错误监听(高级)

针对 JEditorPaneHTMLEditorKit 在解析 HTML 时出现的 ParserError(解析器错误),通常是因为遇到了格式不规范的 HTML 或标签未正确关闭等问题,Swing 默认的 HTML 解析器(基于 Swing 自己的简易解析器,而非浏览器的完整解析器)对 HTML 的容错性较差,遇到错误可能会静默跳过或抛出异常。

以下是几种常见的错误处理及解决方案:


捕获并处理解析异常

使用 try-catch 包裹设置文本的操作:

import javax.swing.*;
import javax.swing.text.html.*;
import java.io.*;
public class HTMLErrorHandler {
    public static void main(String[] args) {
        JEditorPane editorPane = new JEditorPane();
        editorPane.setContentType("text/html");
        editorPane.setEditable(false);
        // 可能包含错误 HTML 的字符串
        String badHtml = "<html><body><p>Test<b>No close</p></html>";
        try {
            editorPane.setText(badHtml);
        } catch (Exception e) {
            System.err.println("HTML 解析错误: " + e.getMessage());
            // 可执行降级策略,如显示纯文本
            editorPane.setText(badHtml.replaceAll("<[^>]*>", ""));
        }
    }
}

自定义 HTMLEditorKit 的错误处理

通过继承 HTMLEditorKit 并覆盖 getParserCallback() 或使用 ParserDelegatorsetErrorHandler 来捕获具体的解析错误。

示例:设置错误处理器

import javax.swing.text.html.*;
import javax.swing.text.html.parser.*;
import javax.swing.text.*;
public class CustomHTMLEditorKit extends HTMLEditorKit {
    @Override
    public ViewFactory getViewFactory() {
        return new HTMLFactory() {
            @Override
            public View create(Element elem) {
                return super.create(elem);
            }
        };
    }
    @Override
    public Document createDefaultDocument() {
        HTMLDocument doc = (HTMLDocument) super.createDefaultDocument();
        // 设置解析器
        ParserDelegator parser = new ParserDelegator() {
            @Override
            public void parse(Reader r, HTMLEditorKit.ParserCallback cb, boolean ignoreCharSet) throws IOException {
                super.parse(r, new ErrorHandlingCallback(cb), ignoreCharSet);
            }
        };
        // 通过反射或其他方式设置解析器
        // 更推荐的方式:使用文档的 setParser 方法(需强制转换)
        return doc;
    }
    // 内部回调类,包裹原始回调并捕获错误
    private static class ErrorHandlingCallback extends HTMLEditorKit.ParserCallback {
        private final HTMLEditorKit.ParserCallback delegate;
        public ErrorHandlingCallback(HTMLEditorKit.ParserCallback delegate) {
            this.delegate = delegate;
        }
        @Override
        public void handleError(String errorMsg, int pos) {
            System.err.println("解析错误 at position " + pos + ": " + errorMsg);
            // 可选择忽略,继续解析
        }
        // 其他回调方法直接委托
        @Override
        public void handleText(char[] data, int pos) {
            delegate.handleText(data, pos);
        }
        @Override
        public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
            delegate.handleStartTag(t, a, pos);
        }
        @Override
        public void handleEndTag(HTML.Tag t, int pos) {
            delegate.handleEndTag(t, pos);
        }
        @Override
        public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) {
            delegate.handleSimpleTag(t, a, pos);
        }
        @Override
        public void handleComment(char[] data, int pos) {
            delegate.handleComment(data, pos);
        }
        @Override
        public void handleEndOfLineString(String eol) {
            delegate.handleEndOfLineString(eol);
        }
    }
}
// 使用时:
JEditorPane editor = new JEditorPane();
editor.setEditorKit(new CustomHTMLEditorKit());
editor.setText("<html><body><p>Test<b>No close</p></html>");

预处理 HTML 以修复常见错误

在传给 JEditorPane 之前,使用简单规则清理 HTML:

public static String sanitizeHtml(String html) {
    if (html == null) return "";
    // 关闭常见的未闭合标签
    html = html.replaceAll("<br>", "<br/>");
    html = html.replaceAll("<img([^>]*)>", "<img$1/>");
    // 确保 img 等自闭合标签正确
    // 移除不合法的属性或标签(根据需要)
    return html;
}
// 使用:
String cleanHtml = sanitizeHtml(badHtml);
editorPane.setText(cleanHtml);

使用更健壮的解析器(如 JSoup)预处理

如果项目允许添加依赖,推荐使用 JSoup 清理 HTML:

import org.jsoup.Jsoup;
import org.jsoup.safety.Safelist;
public static String cleanWithJsoup(String dirtyHtml) {
    // 使用宽松的安全列表,保留大多数标签和属性
    String cleaned = Jsoup.clean(dirtyHtml, Safelist.relaxed());
    // 或者使用更精确的:Safelist.basic() / Safelist.simpleText()
    return cleaned;
}
// 
String safeHtml = cleanWithJsoup(badHtml);
editorPane.setText(safeHtml);

设置全局错误监听(高级)

通过重写 HTMLEditorKit.ParserCallbackhandleError 方法,可以捕获所有解析错误,上面的 ErrorHandlingCallback 已经演示了这一点,你也可以直接在默认的 HTMLEditorKit 中使用:

HTMLEditorKit kit = new HTMLEditorKit();
HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument();
doc.setParser(new ParserDelegator() {
    @Override
    public void parse(Reader r, HTMLEditorKit.ParserCallback cb, boolean ignoreCharSet) throws IOException {
        super.parse(r, new HTMLEditorKit.ParserCallback() {
            @Override
            public void handleError(String errorMsg, int pos) {
                System.err.println("Error: " + errorMsg + " at " + pos);
                // 可以继续向原始回调传递错误,或忽略
                if (cb != null) cb.handleError(errorMsg, pos);
            }
            // 其他方法委托给 cb
            // 注意:所有方法都需要重写并委托
        }, ignoreCharSet);
    }
});
editorPane.setDocument(doc);

方法 适用场景 复杂度
简单 try-catch 仅需基本容错
自定义 Kit + 错误回调 需要记录/跟踪具体解析错误
预处理 HTML(正则/Soup) 可控的输入源,可提前清理
更换解析器(JSoup 预处理) 项目允许依赖,需高质量清理 高(但效果好)

推荐做法

  • HTML 来源不可控(如用户输入),先用 JSoup 清理,再传给 JEditorPane
  • 如果必须使用 Swing 原生解析器,则实现 错误回调 捕获 handleError,避免静默失败。

抱歉,评论功能暂时关闭!