JEditorPaneHTMLEditorKitParserMethodFilter过滤器

wen java案例 3

本文目录导读:

JEditorPaneHTMLEditorKitParserMethodFilter过滤器

  1. 核心概念
  2. 常见的 “Filter” 应用场景
  3. 关键类:HTMLEditorKit.ParserCallback
  4. 如何将过滤器应用到 JEditorPane?
  5. 总结与选择

这是一个关于 Java Swing 中 JEditorPaneHTMLEditorKit 以及解析器/方法过滤器(通常指 HTMLParserparse 方法回调过滤器,或者更常见的 AbstractDocumentParser/HTMLDocument.Parser 中的回调)的深入技术话题,开发者想要实现的是:在 JEditorPane 加载或解析 HTML 时,拦截、过滤或修改特定的 HTML 元素(如标签、属性、文本),而不是单纯地显示 HTML

为了帮助你更精确地解决问题,我将从几个不同的“过滤器”含义来解释,并提供代码示例。

核心概念

  1. JEditorPane: Swing 的富文本组件,支持 HTML 3.2(通过 HTMLEditorKit)。
  2. HTMLEditorKit: 负责将 HTML 字符串解析并转换为 Swing 的文档模型(HTMLDocument)。
  3. 解析器(Parser): javax.swing.text.html.parser.ParserDelegatorDocumentParser,它是实际的 HTML 解析引擎,它会在解析过程中回调各种方法(如 handleStartTaghandleTexthandleEndTag 等)。
  4. Callback / Filter: 你在解析器回调中插入的代码,用于决定是否保留、修改或忽略某个 HTML 元素。

常见的 “Filter” 应用场景

  1. 安全过滤(XSS 防护): 禁止 <script><iframe>onclick 等危险事件。
  2. 标签黑/白名单: 只允许 <b><i><a>,禁止 <img>
  3. 属性修改: 强制将所有链接的 target 设为 _self
  4. 文本替换: 将特定文本替换或高亮显示。
  5. 自定义渲染: 将某些标签替换为 Swing 组件。

关键类:HTMLEditorKit.ParserCallback

这是实现过滤器的核心,你需要创建一个继承自 HTMLEditorKit.ParserCallback 的类,并重写相关方法。

基础示例:一个只允许 <b><i> 标签的过滤器

import javax.swing.text.*;
import javax.swing.text.html.*;
import javax.swing.text.html.parser.*;
import java.io.*;
public class SimpleHTMLFilter extends HTMLEditorKit.ParserCallback {
    // 允许的标签列表
    private static final java.util.Set<HTML.Tag> ALLOWED_TAGS =
        new java.util.HashSet<>(java.util.Arrays.asList(HTML.Tag.B, HTML.Tag.I, HTML.Tag.U));
    @Override
    public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
        if (ALLOWED_TAGS.contains(t)) {
            super.handleStartTag(t, a, pos);
        }
        // else: 忽略不允许的标签
    }
    @Override
    public void handleEndTag(HTML.Tag t, int pos) {
        if (ALLOWED_TAGS.contains(t)) {
            super.handleEndTag(t, pos);
        }
    }
    @Override
    public void handleText(char[] data, int pos) {
        super.handleText(data, pos); // 文本总是允许的
    }
    @Override
    public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) {
        // 处理自闭和标签如 <br>、<img>
        if (ALLOWED_TAGS.contains(t)) {
            super.handleSimpleTag(t, a, pos);
        }
    }
    @Override
    public void handleComment(char[] data, int pos) {
        // 默认忽略注释,如果你想保留注释,可以 uncomment 下一行
        // super.handleComment(data, pos);
    }
    @Override
    public void handleError(String errorMsg, int pos) {
        // 打印解析错误,但不中断
        System.err.println("解析错误: " + errorMsg + " at position: " + pos);
    }
}

如何将过滤器应用到 JEditorPane?

你不能直接将自定义的 ParserCallback 注入到标准的 HTMLEditorKit 中因为默认的 HTMLEditorKit 使用它自己内部的回调(HTMLDocument 的构建器)来构建文档。

方法:替换解析器回调

你需要创建一个自定义的 HTMLEditorKit,并覆盖 getParserCallback 方法(或者更准确地说,覆盖 createDocument 或使用 ParserDelegator 并传入你自己的 ParserCallback)。

更简单的做法:重写 ViewFactory 或使用 DocumentParser 手动解析

由于直接替换 HTMLEditorKit 解析器内部回调比较复杂且容易出错,更常见的方法是:

  1. 手动解析 HTML 字符串,使用 ParserDelegator 和你的 FilterCallback 生成一个干净的 HTML 字符串。
  2. 再将其设置到 JEditorPane

或者,可以使用一个较高级的库,Swing HTML Parsing Library (JSoup) 进行预处理,然后将干净的 HTML 交给 JEditorPane

完整示例:使用 JSoup 进行预处理(推荐)

这是最稳定、最清晰的方式,尤其适合复杂的过滤需求。

import org.jsoup.Jsoup;
import org.jsoup.safety.Safelist;
import javax.swing.*;
import javax.swing.text.html.HTMLEditorKit;
import java.io.IOException;
public class JEditorPaneWithJsoupFilter {
    public static void main(String[] args) {
        JFrame frame = new JFrame("JEditorPane JSoup Filter Demo");
        JEditorPane editorPane = new JEditorPane();
        editorPane.setEditable(false);
        editorPane.setContentType("text/html");
        // 使用 JSoup 清洁 HTML
        String dirtyHtml = "<html><body><script>alert('XSS')</script>" +
                           "<p>This is <b>bold</b> and <i>italic</i>.</p>" +
                           "<a href='#' onclick='alert(1)'>Link</a>" +
                           "<img src='x' onerror='alert(2)'></body></html>";
        // 使用 JSoup 的 Safelist(白名单)
        Safelist safelist = Safelist.none()
                .addTags("p", "b", "i", "u", "a", "br")
                .addAttributes("a", "href") // 只允许 href 属性
                .addProtocols("a", "href", "http", "https"); // 只允许 http/https 链接
        String cleanHtml = Jsoup.clean(dirtyHtml, safelist);
        // 确保有基本的 HTML 结构
        cleanHtml = "<html><body>" + cleanHtml + "</body></html>";
        System.out.println("Cleaned HTML: " + cleanHtml);
        editorPane.setText(cleanHtml);
        frame.add(new JScrollPane(editorPane));
        frame.setSize(400, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

总结与选择

方法 复杂性 灵活性 性能 适用场景
JSoup 预处理 极高 中等 推荐,适用于大多数过滤、修改、安全清洗。
自定义 ParserCallback 需要直接操作 Swing 文档结构,或对性能要求极高。
覆盖 HTMLEditorKit 不推荐,除非你非常熟悉 Swing HTML 内部机制。

如果你的需求是“在解析过程中过滤”,例如基于位置或上下文做复杂的决策,且不想使用外部库(JSoup),那么你需要深入研究 javax.swing.text.html.parser.ParserDelegatorDocumentParser,但通常,用 JSoup 做预处理是最佳实践

如果你有更具体的过滤需求(只允许 <table> 标签且只能有 border='1' 属性”),请提供细节,我可以给出针对性的代码。

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