本文目录导读:

我来解释一下 JEditorPane、HTMLEditorKit 和 Parser 之间的实体解析机制。
结构关系
JEditorPane -> HTMLEditorKit -> Parser (ParserDelegator)
-> HTMLReader (Callback)
-> ViewFactory
实体解析流程
基础设置
JEditorPane editor = new JEditorPane();
editor.setContentType("text/html");
editor.setText("<html><body>& < > "</body></html>");
HTMLEditorKit 的解析机制
// HTMLEditorKit 内部使用 ParserDelegator
public class HTMLEditorKit extends StyledEditorKit {
// 默认解析器
private static final DefaultHTMLParser defaultParser = new DefaultHTMLParser();
public Parser getParser() {
return new ParserDelegator();
}
// 创建回调处理器
protected HTMLEditorKit.HTMLReader getCallback() {
return new HTMLReader();
}
}
实体解析的核心实现
内置实体映射
public class HTMLEditorKit.Parser {
// 预定义的实体映射表
private static final Hashtable<String, Character> entityTable = new Hashtable<>();
static {
entityTable.put("amp", '&');
entityTable.put("lt", '<');
entityTable.put("gt", '>');
entityTable.put("quot", '"');
entityTable.put("apos", '\'');
entityTable.put("nbsp", (char)160);
entityTable.put("copy", (char)169);
entityTable.put("reg", (char)174);
// ... 更多实体
}
}
ParserDelegator 解析逻辑
public class ParserDelegator extends HTMLEditorKit.Parser {
private static final char[] REPLACEMENT_CHARS = {
'&', '<', '>', '"', '\'', ' '
};
@Override
public void parse(Reader r, HTMLEditorKit.ParserCallback cb, boolean ignoreCharSet) {
// 1. 读取 HTML 内容
// 2. 识别 &xxx; 模式
// 3. 查表替换
// 4. 调用 callback 方法
}
}
实际解析过程演示
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import javax.swing.text.html.parser.*;
import java.io.*;
public class EntityParsingDemo {
public static void main(String[] args) {
JEditorPane editor = new JEditorPane();
editor.setContentType("text/html");
// 包含各种实体的 HTML
String html = "<html><body>" +
"<p>& < > " '</p>" +
"<p>© © ©</p>" +
"<p>普通文本 & 更多</p>" +
"</body></html>";
editor.setText(html);
System.out.println("解析后的文本: " + editor.getText());
// 自定义解析观察
HTMLEditorKit kit = (HTMLEditorKit) editor.getEditorKit();
HTMLEditorKit.Parser parser = kit.getParser();
try {
StringReader reader = new StringReader(html);
parser.parse(reader, new HTMLEditorKit.ParserCallback() {
@Override
public void handleText(char[] data, int pos) {
System.out.println("解析文本: " + new String(data));
}
@Override
public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
System.out.println("开始标签: " + t);
}
@Override
public void handleEndTag(HTML.Tag t, int pos) {
System.out.println("结束标签: " + t);
}
@Override
public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) {
System.out.println("简单标签: " + t);
}
}, false);
} catch (Exception e) {
e.printStackTrace();
}
}
}
自定义实体处理
public class CustomHTMLEditorKit extends HTMLEditorKit {
@Override
public Parser getParser() {
return new ParserDelegator() {
@Override
public void parse(Reader r, ParserCallback cb, boolean ignoreCharSet)
throws IOException {
// 自定义预处理
BufferedReader br = new BufferedReader(r);
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
// 添加自定义实体
String content = sb.toString()
.replace("&myentity;", "自定义值")
.replace("&custom;", "custom value");
// 调用父类解析
super.parse(new StringReader(content), cb, ignoreCharSet);
}
};
}
}
实体解析的关键类
| 类名 | 作用 |
|---|---|
ParserDelegator |
默认解析器实现 |
DTD |
HTML DTD 定义 |
HTMLEditorKit.ParserCallback |
解析回调接口 |
HTMLReader |
内部回调实现 |
HTML.Attribute |
属性常量定义 |
HTML.Tag |
标签常量定义 |
Debug 示例
import javax.swing.text.html.parser.*;
public class EntityDebugger {
public static void main(String[] args) throws Exception {
// 查看所有内置实体
DTD dtd = DTD.getDTD("html32");
System.out.println("=== 实体列表 ===");
// 通过反射获取实体表
java.lang.reflect.Field entitiesField = DTD.class.getDeclaredField("entityHash");
entitiesField.setAccessible(true);
@SuppressWarnings("unchecked")
java.util.Hashtable<String, Entity> entities =
(java.util.Hashtable<String, Entity>) entitiesField.get(dtd);
entities.forEach((name, entity) -> {
System.out.println(name + " -> " + (char)entity.data);
});
// 测试自定义实体
String html = "&unknown; &test; &";
// unknown 和 test 不会被解析
// & 会被解析为 &
}
}
注意事项
- 实体类型:支持命名实体(&)和数字实体(&)
- Unicode 支持:支持 Unicode 编码实体(©)
- 大小写敏感:实体名称对大小写敏感
- 未知实体:未知实体保留原样
- 性能考虑:大量实体解析可能影响性能
常见问题解决
// 处理特殊字符
editor.setText(text.replace("&", "&")); // 手动转义
// 禁用实体解析
editor.getDocument().putProperty("IgnoreCharset", Boolean.TRUE);
// 使用 setText 而不是 write
editor.setText(html); // 自动解析
editor.write(writer); // 可能不会解析实体
这就是 JEditorPane 中 HTMLEditorKit 和 Parser 的实体解析机制,理解这个机制对于正确处理 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直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播