JEditorPaneHTMLEditorKitParserOutput输出处理

wen java案例 3

本文目录导读:

JEditorPaneHTMLEditorKitParserOutput输出处理

  1. 基础架构理解
  2. 核心处理方式
  3. 保存和恢复 HTML 内容
  4. 自定义解析器输出处理器
  5. 实际应用示例
  6. 常见问题与解决方案
  7. 最佳实践

针对 JEditorPaneHTMLEditorKit 和 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() {
        // 这里执行实际的解析和输出处理
    }
});

最佳实践

  1. 始终在EDT线程中处理UI相关操作
  2. 对大文档使用异步解析
  3. 关闭自动加载图片editorPane.setAutoscrolls(false)
  4. 使用HTMLDocument而不是直接操作文本
  5. 考虑使用第三方库(如jsoup)处理复杂HTML

这套方案涵盖了从基础解析到高级处理的各种场景,可以根据具体需求选择合适的实现方式。

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