Java中富文本转markdown

实现富文本即html语法转md,要求是尽可能展示效果一样,可以有少许误差,另外只实现了html中的body转md,其他标签如head等未实现。

大致思路是:通过jsoup工具获取html节点,再穷举替换。前提是熟悉html以及md语法

依赖如下:

XML 复制代码
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.16.1</version>
        </dependency>

代码如下:

java 复制代码
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.util.ArrayList;
import java.util.List;

public class Html2MarkdownUtil {

    public static void main(String[] args) {
        String html = "<p style=\"padding: 0; margin: 10px 0; line-height: 1.5; font-size: 16px;\"><b style=\"padding: 0; margin: 0;\">Hello<font color=\"#c24f4a\" style=\"padding: 0; margin: 0;\">world</font></b></p>";
        System.out.println(parseHtml2Markdown(html));
    }

    /**
     * 解析html2md
     *
     * @param html html
     * @return {@link String}
     */
    public static String parseHtml2Markdown(String html) {
        Document doc = Jsoup.parse(html);
        StringBuilder sb = new StringBuilder();
        for (Element element : doc.body().children()) {
            HtmlElement htmlElement = new HtmlElement(element);
            sb.append(htmlElement.getMarkdownText());
        }
        return sb.toString();
    }

    /**
     * 标记文本
     *
     * @param element 要素
     * @return {@link String}
     */
    public static String toMarkdownText(Element element) {
        StringBuilder sb = new StringBuilder();
        String tagName = element.tagName().toLowerCase();
        String text = element.ownText();
        switch (tagName) {
            case "h1":
                sb.append("# ").append(text);
                break;
            case "h2":
                sb.append("## ").append(text);
                break;
            case "h3":
                sb.append("### ").append(text);
                break;
            case "h4":
                sb.append("#### ").append(text);
                break;
            case "h5":
                sb.append("##### ").append(text);
                break;
            case "h6":
                sb.append("###### ").append(text);
                break;
            case "p":
            case "font":
            case "b":
            case "span":
                sb.append(text);
                break;
            case "ul":
                for (Element child : element.children()) {
                    sb.append("* ").append(child.text().trim()).append("\n");
                }
                break;
            case "ol":
                int index = 1;
                for (Element child : element.children()) {
                    sb.append(index).append(". ").append(child.text().trim()).append("\n");
                    index++;
                }
                break;
            case "a":
                sb.append("[").append(text).append("](").append(element.attr("href")).append(")");
                break;
            case "strong":
                sb.append("**").append(text).append("**");
                break;
            case "em":
                sb.append("_").append(text).append("_");
                break;
            case "blockquote":
                sb.append("> ").append(text);
                break;
            case "img":
                sb.append("![");
                if (element.hasAttr("alt")) {
                    sb.append(element.attr("alt"));
                }
                sb.append("](").append(element.attr("src")).append(")");
                break;
            default:
                break;
        }
        return sb.toString();
    }

    @Data
    public static class HtmlElement {

        private Element element;
        private String tagName;
        private String ownText;
        private boolean isNewline;
        private List<HtmlElement> children;

        public HtmlElement(Element element) {
            this.element = element;
            this.tagName = element.tagName().toLowerCase();
            this.ownText = element.ownText();
            this.isNewline = isNewline();
            if (!StringUtils.equalsAny(this.tagName, "ul", "ol")) {
                Elements children = element.children();
                if (children.size() > 0) {
                    this.children = new ArrayList<>();
                    for (Element child : children) {
                        this.children.add(new HtmlElement(child));
                    }
                }
            }
        }

        public boolean isNewline() {
            return StringUtils.equalsAny(tagName, "h1", "h2", "h3", "h4", "h5", "h6", "p", "ul", "ol", "blockquote");
        }

        public String getMarkdownText() {
            StringBuilder sb = new StringBuilder();
            sb.append(toMarkdownText(element));
            if (children != null && children.size() > 0) {
                for (HtmlElement child : children) {
                    sb.append(child.getMarkdownText());
                }
            }
            if (isNewline) {
                sb.append("\n");
            }
            return sb.toString();
        }
    }
}
相关推荐
q***471815 分钟前
Spring Boot 3.3.4 升级导致 Logback 之前回滚策略配置不兼容问题解决
java·spring boot·logback
毕设源码-邱学长1 小时前
【开题答辩全过程】以 基于SpringBoot的医院血库管理系统设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
菠菠萝宝1 小时前
【Java手搓RAGFlow】-9- RAG对话实现
java·开发语言·人工智能·llm·jenkins·openai
清风徐来QCQ1 小时前
Spring Boot 静态资源路径映射
java·spring boot·后端
科威舟的代码笔记1 小时前
第10讲:Stream实战与陷阱——综合案例与最佳实践
java·开发语言
程序定小飞2 小时前
基于springboot的体育馆使用预约平台的设计与实现
java·开发语言·spring boot·后端·spring
5***79002 小时前
Java虚拟现实开发
java·开发语言·vr
计算机毕业设计小途2 小时前
计算机毕业设计推荐:基于SpringBoot的水产养殖管理系统【Java+spring boot+MySQL、Java项目、Java毕设、Java项目定制定做】
java·spring boot·mysql
养乐多07222 小时前
【Java】异常
java·开发语言
2***57422 小时前
Java数据分析实战
java·python·数据分析