本文目录导读:

这个错误信息看起来是 Java Swing 中 JEditorPane 和 HTMLEditorKit 解析 HTML 时遇到的一个问题。“非法选择器” 通常指的是 HTML 解析器遇到了无法识别的或格式错误的 CSS 选择器。
根本原因
JEditorPane 和 HTMLEditorKit 使用的是过时且不完整的 HTML 3.2 / 4.0 解析器(带有有限的 CSS 支持),当你尝试加载包含现代 CSS 或非标准选择器的 HTML 内容时,解析器可能会抛出 IllegalSelector 错误。
常见触发场景
- 使用了现代 CSS 选择器(如
nth-child,last-of-type,:before,:after等)。 - 复杂的或非标准的 CSS 类/ID 命名(例如包含特殊字符、数字开头、CSS 保留关键字)。
- HTML 中嵌入了
<style>,且内容包含 Java 解析器不认识的选择器语法。 - 使用了自定义的
HTMLEditorKit,但扩展的解析方法中存在 bug。
解决方案
简化 CSS / 避免现代选择器
HTML 内容是你自己生成的,请确保只使用基本的选择器:
- 标签选择器:
body,p,div - 类选择器:
.classname(确保类名以字母开头,只包含字母、数字、连字符、下划线) - ID 选择器:
#idname - 后代选择器:
div p(简单的空格分隔)
避免使用:
- 伪类(
hover,first-child) - 伪元素(
:before) - 属性选择器(
[type="text"]) - 组合器(
>、、)
删除或注释掉 <style>
如果是为了渲染简单文本,直接移除所有 CSS 样式,或将其内联到元素的 style 属性中(<p style="color:red">)通常更安全。
捕获异常并降级处理
HTML 来源不可控(例如用户输入或外部网页),需要捕获异常,避免程序崩溃:
import javax.swing.*;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
import java.io.StringReader;
public class SafeHtmlViewer {
public static void main(String[] args) {
JEditorPane editorPane = new JEditorPane();
editorPane.setContentType("text/html");
// 设置 a 自定义的 HTMLEditorKit 来捕获异常
HTMLEditorKit kit = new HTMLEditorKit() {
@Override
public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException {
try {
super.read(in, doc, pos);
} catch (Exception e) {
// 记录错误,但不中断执行
System.err.println("HTML parse error: " + e.getMessage());
// 可选:尝试降级为纯文本
}
}
};
// 简化样式表(可选)
StyleSheet styleSheet = new StyleSheet();
styleSheet.addRule("p { margin: 0; }");
kit.setStyleSheet(styleSheet);
editorPane.setEditorKit(kit);
// 示例:可能包含非法选择器的 HTML
String unsafeHtml = "<html><body><p style='color:red'>Hello</p></body></html>";
try {
editorPane.read(new StringReader(unsafeHtml), "text/html");
} catch (Exception e) {
e.printStackTrace();
}
}
}
升级到现代 Swing 组件(推荐)
JEditorPane 的 HTML 渲染能力非常有限,如果项目对 HTML 展示有较高要求(现代 CSS、复杂布局),强烈建议:
- 使用
JWebView(JavaFX):通过 javafx.scene.web.WebView 嵌入到 Swing 中(使用 JFXPanel)。
- 使用第三方库:如 Flying Saucer(
xhtmlrenderer),它对 CSS 2.1 支持更好。
- 使用纯文本或 JLabel只是简单富文本,考虑使用
JLabel 的 HTML 支持。
示例:使用 Flying Saucer(更好的 CSS 支持)
<!-- Maven 依赖 -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-core</artifactId>
<version>9.9.0</version>
</dependency>
import org.xhtmlrenderer.swing.Java2DRenderer;
import org.xhtmlrenderer.resource.FSEntityResolver;
// 渲染 XHTML 到 BufferedImage 或直接输出到 Graphics2D
快速排查步骤
- 打印出 HTML:检查传递给
setText() 或 read() 的 HTML 字符串中是否有任何 CSS 选择器。
- 测试简化版:将 HTML 简化为
<html><body><p>test</p></body></html>,看是否还会报错。
- 检查自定义 EditorKit:如果你继承了
HTMLEditorKit 并重写了 getParser() 方法,检查你的自定义解析器实现。
这个错误的核心是 JEditorPane 的 CSS 解析能力太弱。最直接的解决方案是移除非标准 CSS(尤其是伪类/伪元素/属性选择器),或者考虑使用更现代的 HTML 渲染方案。
如果是为了渲染简单文本,直接移除所有 CSS 样式,或将其内联到元素的 style 属性中(<p style="color:red">)通常更安全。
捕获异常并降级处理
HTML 来源不可控(例如用户输入或外部网页),需要捕获异常,避免程序崩溃:
import javax.swing.*;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
import java.io.StringReader;
public class SafeHtmlViewer {
public static void main(String[] args) {
JEditorPane editorPane = new JEditorPane();
editorPane.setContentType("text/html");
// 设置 a 自定义的 HTMLEditorKit 来捕获异常
HTMLEditorKit kit = new HTMLEditorKit() {
@Override
public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException {
try {
super.read(in, doc, pos);
} catch (Exception e) {
// 记录错误,但不中断执行
System.err.println("HTML parse error: " + e.getMessage());
// 可选:尝试降级为纯文本
}
}
};
// 简化样式表(可选)
StyleSheet styleSheet = new StyleSheet();
styleSheet.addRule("p { margin: 0; }");
kit.setStyleSheet(styleSheet);
editorPane.setEditorKit(kit);
// 示例:可能包含非法选择器的 HTML
String unsafeHtml = "<html><body><p style='color:red'>Hello</p></body></html>";
try {
editorPane.read(new StringReader(unsafeHtml), "text/html");
} catch (Exception e) {
e.printStackTrace();
}
}
}
升级到现代 Swing 组件(推荐)
JEditorPane 的 HTML 渲染能力非常有限,如果项目对 HTML 展示有较高要求(现代 CSS、复杂布局),强烈建议:
- 使用
JWebView(JavaFX):通过javafx.scene.web.WebView嵌入到 Swing 中(使用JFXPanel)。 - 使用第三方库:如 Flying Saucer(
xhtmlrenderer),它对 CSS 2.1 支持更好。 - 使用纯文本或 JLabel只是简单富文本,考虑使用
JLabel的 HTML 支持。
示例:使用 Flying Saucer(更好的 CSS 支持)
<!-- Maven 依赖 -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-core</artifactId>
<version>9.9.0</version>
</dependency>
import org.xhtmlrenderer.swing.Java2DRenderer; import org.xhtmlrenderer.resource.FSEntityResolver; // 渲染 XHTML 到 BufferedImage 或直接输出到 Graphics2D
快速排查步骤
- 打印出 HTML:检查传递给
setText()或read()的 HTML 字符串中是否有任何 CSS 选择器。 - 测试简化版:将 HTML 简化为
<html><body><p>test</p></body></html>,看是否还会报错。 - 检查自定义 EditorKit:如果你继承了
HTMLEditorKit并重写了getParser()方法,检查你的自定义解析器实现。
这个错误的核心是 JEditorPane 的 CSS 解析能力太弱。最直接的解决方案是移除非标准 CSS(尤其是伪类/伪元素/属性选择器),或者考虑使用更现代的 HTML 渲染方案。