最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實現將markdown轉換為html

 更新時間:2025年11月05日 09:14:19   作者:張鐵牛  
最近因為項目需求需要將AI輸出的結果導出到word中, 但AI輸出的格式為markdown格式,所以本文我們就來看看如何使用Java實現先將markdown轉換為html吧

1. 簡介

最近因為項目需求需要將AI輸出的結果導出到word中, 但AI輸出的格式為markdown格式,因為word展示內容的時候需要有相應的格式(標題, 段落, 列表, 表格等), 所以不能直接將markdown輸出到word中, 否則word中展示的就是markdown純文本了, 調研一番后發(fā)現如果想要word展示效果好一點的話需要分成兩步

  • markdownhtml
  • htmlooxml(Office Open XML) word內容,word元信息本身就是個xml)

所以本章先實現第一步 markdownhtml, 使用的組件為flexmark

2. 環(huán)境信息

為了兼容更多的場景, 所以并沒有用一些高版本的SDK, 信息如下

Java: 8
Flexmark: 0.60.2

3. Maven

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ldx</groupId>
    <artifactId>md2html</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <flexmark.version>0.60.2</flexmark.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.vladsch.flexmark</groupId>
            <artifactId>flexmark</artifactId>
            <version>${flexmark.version}</version>
        </dependency>
        <dependency>
            <groupId>com.vladsch.flexmark</groupId>
            <artifactId>flexmark-ext-tables</artifactId>
            <version>${flexmark.version}</version>
        </dependency>
    </dependencies>
</project>

4. Markdown轉Html

import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.data.MutableDataSet;

public class MarkdownToHtml {
    public static String convertMarkdownToHtml(String markdown) {
        // 創(chuàng)建配置集
        MutableDataSet options = new MutableDataSet();
        // 創(chuàng)建解析器和渲染器
        Parser parser = Parser.builder(options).build();
        HtmlRenderer renderer = HtmlRenderer.builder(options).build();
        // 解析 Markdown 文本
        Node document = parser.parse(markdown);
        // 渲染為 HTML
        return renderer.render(document);
    }

    public static void main(String[] args) {
        String markdown = "## 嘉文四世\n" + "\n" + "> 德瑪西亞\n" + "\n" + "**給我找些更強的敵人!**";
        final String html = convertMarkdownToHtml(markdown);
        System.out.println(html);
    }
}

測試結果如下:

<h2>嘉文四世</h2>
<blockquote>
<p>德瑪西亞</p>
</blockquote>
<p><strong>給我找些更強的敵人!</strong></p>

5. 高級用法

5.1 啟用Table擴展

flexmark 支持多種擴展,需要通過 Extension 注冊, 比如啟用表格語法, flexmark默認沒有啟用表格語法比如測試

public static void main(String[] args) {
    String markdown = "| 列1   | 列2   |\n" + "| ----- | ----- |\n" + "| 數據1 | 數據2 |";
    final String html = convertMarkdownToHtml(markdown);
    System.out.println(html);
}

測試結果如下:

<p>| 列1   | 列2   |
| ----- | ----- |
| 數據1 | 數據2 |</p>

沒有將表格轉換為html table標簽, 所以需要啟用表格擴展, 如下:

MutableDataSet options = new MutableDataSet();
// 啟用表格擴展,支持 Markdown 表格語法
options.set(Parser.EXTENSIONS, Collections.singletonList(TablesExtension.create()));
// 禁用跨列
options.set(TablesExtension.COLUMN_SPANS, false);
// 表頭固定為 1 行
options.set(TablesExtension.MIN_HEADER_ROWS, 1);
options.set(TablesExtension.MAX_HEADER_ROWS, 1);
// 自動補全缺失列、丟棄多余列
options.set(TablesExtension.APPEND_MISSING_COLUMNS, true);
options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true);

測試結果如下:

<table>
<thead>
<tr><th>列1</th><th>列2</th></tr>
</thead>
<tbody>
<tr><td>數據1</td><td>數據2</td></tr>
</tbody>
</table>

5.2 標簽屬性擴展

flexmark支持對標簽屬性的操作, 需要實現其AttributeProviderFactory類, 比如給對應標簽添加class屬性, 如下:

HtmlRenderer renderer = HtmlRenderer.builder(options)
  .attributeProviderFactory(new IndependentAttributeProviderFactory() {
    @Override
    public @NotNull AttributeProvider apply(@NotNull LinkResolverContext context) {
      return (node, part, attributes) -> {
        // 標題
        if (node instanceof Heading) {
          Heading heading = (Heading) node;
          attributes.addValue("class", "heading" + heading.getLevel());
        }

        // 正文
        if (node instanceof Text) {
          attributes.addValue("class", "Normal");
        }

        // 段落
        if (node instanceof Paragraph) {
          attributes.addValue("class", "paragraph");
        }

        // 無序列表
        if (node instanceof BulletList) {
          attributes.addValue("class", "bulletList");
        }

        // 有序列表
        if (node instanceof OrderedList) {
          attributes.addValue("class", "bulletList");
        }

        // 表格
        if (node instanceof TableBlock) {
          attributes.addValue("class", "tableBlock");
        }
      };

    }
  })
  .build();

測試如下內容:

public static void main(String[] args) {
    String markdown = "## 嘉文四世\n" + "\n" + "> 德瑪西亞\n" + "\n" + "**給我找些更強的敵人!**\n" + "\n" + "| 列1   | 列2   |\n" + "| ----- | ----- |\n" + "| 數據1 | 數據2 |";
    final String html = convertMarkdownToHtml(markdown);
    System.out.println(html);
}

測試結果如下:

<h2 class="heading2">嘉文四世</h2>
<blockquote>
<p class="paragraph">德瑪西亞</p>
</blockquote>
<p class="paragraph"><strong>給我找些更強的敵人!</strong></p>
<table class="tableBlock">
<thead>
<tr><th>列1</th><th>列2</th></tr>
</thead>
<tbody>
<tr><td>數據1</td><td>數據2</td></tr>
</tbody>
</table>

5.3 完善Html結構

上述的測試結果中輸出的都是markdown語句翻譯后的html代碼塊, 并不是一個完整的html頁面內容, 比如要將結果輸出成html文件并展示的話還需要html完整的骨架標簽如:<html><body>等, 這時候就需要使用jsoup進行優(yōu)化

添加對應的坐標

<jsoup.version>1.17.2</jsoup.version>

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>${jsoup.version}</version>
</dependency>

完善html結構

public static String wrapperHtml(String htmlContent) {
    org.jsoup.nodes.Document jsoupDoc = Jsoup.parse(htmlContent);
    jsoupDoc.outputSettings()
        // 內容輸出時遵循XML語法規(guī)則
        .syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml)
        // 內容轉義時遵循xhtml規(guī)范
        .escapeMode(Entities.EscapeMode.xhtml)
        // 禁用格式化輸出
        .prettyPrint(false);
    return jsoupDoc.html();
}

public static void main(String[] args) {
    String markdown = "## 嘉文四世\n" + "\n" + "> 德瑪西亞\n" + "\n" + "**給我找些更強的敵人!**\n" + "\n" + "| 列1   | 列2   |\n" + "| ----- | ----- |\n" + "| 數據1 | 數據2 |";
    final String html = convertMarkdownToHtml(markdown);
    final String wrappedHtml = wrapperHtml(html);
    System.out.println(wrappedHtml);
}

測試結果如下:

<html><head></head><body><h2 class="heading2">嘉文四世</h2>
<blockquote>
<p class="paragraph">德瑪西亞</p>
</blockquote>
<p class="paragraph"><strong>給我找些更強的敵人!</strong></p>
<table class="tableBlock">
<thead>
<tr><th>列1</th><th>列2</th></tr>
</thead>
<tbody>
<tr><td>數據1</td><td>數據2</td></tr>
</tbody>
</table>
</body></html>

6. 完整測試代碼

package md2html;

import com.vladsch.flexmark.ast.BulletList;
import com.vladsch.flexmark.ast.Heading;
import com.vladsch.flexmark.ast.OrderedList;
import com.vladsch.flexmark.ast.Paragraph;
import com.vladsch.flexmark.ast.Text;
import com.vladsch.flexmark.ext.tables.TableBlock;
import com.vladsch.flexmark.ext.tables.TablesExtension;
import com.vladsch.flexmark.html.AttributeProvider;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.html.IndependentAttributeProviderFactory;
import com.vladsch.flexmark.html.renderer.LinkResolverContext;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.data.MutableDataSet;
import org.jetbrains.annotations.NotNull;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Entities;

import java.util.Collections;

public class MarkdownToHtml {
    public static String convertMarkdownToHtml(String markdown) {
        // 創(chuàng)建配置集
        MutableDataSet options = new MutableDataSet();
        // 啟用表格擴展,支持 Markdown 表格語法
        options.set(Parser.EXTENSIONS, Collections.singletonList(TablesExtension.create()));
        // 禁用跨列
        options.set(TablesExtension.COLUMN_SPANS, false);
        // 表頭固定為 1 行
        options.set(TablesExtension.MIN_HEADER_ROWS, 1);
        options.set(TablesExtension.MAX_HEADER_ROWS, 1);
        // 自動補全缺失列、丟棄多余列
        options.set(TablesExtension.APPEND_MISSING_COLUMNS, true);
        options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true);
        // 創(chuàng)建解析器和渲染器
        Parser parser = Parser.builder(options)
                              .build();
        HtmlRenderer renderer = HtmlRenderer.builder(options)
                                            .attributeProviderFactory(new IndependentAttributeProviderFactory() {
                                                @Override
                                                public @NotNull AttributeProvider apply(@NotNull LinkResolverContext context) {
                                                    return (node, part, attributes) -> {
                                                        // 標題
                                                        if (node instanceof Heading) {
                                                            Heading heading = (Heading) node;
                                                            attributes.addValue("class", "heading" + heading.getLevel());
                                                        }

                                                        // 正文
                                                        if (node instanceof Text) {
                                                            attributes.addValue("class", "Normal");
                                                        }

                                                        // 段落
                                                        if (node instanceof Paragraph) {
                                                            attributes.addValue("class", "paragraph");
                                                        }

                                                        // 無序列表
                                                        if (node instanceof BulletList) {
                                                            attributes.addValue("class", "bulletList");
                                                        }

                                                        // 有序列表
                                                        if (node instanceof OrderedList) {
                                                            attributes.addValue("class", "bulletList");
                                                        }

                                                        // 表格
                                                        if (node instanceof TableBlock) {
                                                            attributes.addValue("class", "tableBlock");
                                                        }
                                                    };

                                                }
                                            })
                                            .build();

        // 解析 Markdown 文本
        Node document = parser.parse(markdown);
        // 渲染為 HTML
        return renderer.render(document);
    }

    public static String wrapperHtml(String htmlContent) {
        org.jsoup.nodes.Document jsoupDoc = Jsoup.parse(htmlContent);
        jsoupDoc.outputSettings()
                // 內容輸出時遵循XML語法規(guī)則
                .syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml)
                // 內容轉義時遵循xhtml規(guī)范
                .escapeMode(Entities.EscapeMode.xhtml)
                // 禁用格式化輸出
                .prettyPrint(false);
        return jsoupDoc.html();
    }

    public static void main(String[] args) {
        String markdown = "## 嘉文四世\n" + "\n" + "> 德瑪西亞\n" + "\n" + "**給我找些更強的敵人!**\n" + "\n" + "| 列1   | 列2   |\n" + "| ----- | ----- |\n" + "| 數據1 | 數據2 |";
        final String html = convertMarkdownToHtml(markdown);
        final String wrappedHtml = wrapperHtml(html);
        System.out.println(wrappedHtml);
    }
}

7. 封裝工具類

為了更方便的使用flexmark, 我將其常用的方法封裝成鏈式調用的工具類, 內容如下:

import com.vladsch.flexmark.ast.BlockQuote;
import com.vladsch.flexmark.ast.BulletList;
import com.vladsch.flexmark.ast.Code;
import com.vladsch.flexmark.ast.Emphasis;
import com.vladsch.flexmark.ast.FencedCodeBlock;
import com.vladsch.flexmark.ast.Heading;
import com.vladsch.flexmark.ast.Image;
import com.vladsch.flexmark.ast.IndentedCodeBlock;
import com.vladsch.flexmark.ast.Link;
import com.vladsch.flexmark.ast.ListItem;
import com.vladsch.flexmark.ast.OrderedList;
import com.vladsch.flexmark.ast.Paragraph;
import com.vladsch.flexmark.ast.StrongEmphasis;
import com.vladsch.flexmark.ast.ThematicBreak;
import com.vladsch.flexmark.ext.tables.TableBlock;
import com.vladsch.flexmark.ext.tables.TablesExtension;
import com.vladsch.flexmark.html.AttributeProvider;
import com.vladsch.flexmark.html.AttributeProviderFactory;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.html.IndependentAttributeProviderFactory;
import com.vladsch.flexmark.html.renderer.LinkResolverContext;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Document;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.data.MutableDataSet;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Entities;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collections;

/**
 * markdown 工具類
 *
 * @author ludangxin
 * @since 2025/10/14
 */
@Slf4j
public class Markdowns {

    public static MarkdownBuilder builder(InputStream inputStream, String charset) {
        String markdownContent = readMarkdownContent(inputStream, charset);
        return builder(markdownContent);
    }

    public static MarkdownBuilder builder(InputStream inputStream) {
        String markdownContent = readMarkdownContent(inputStream);
        return builder(markdownContent);
    }

    public static MarkdownBuilder builder(File file) {
        String markdownContent = readMarkdownContent(file);
        return builder(markdownContent);
    }

    public static MarkdownBuilder builder(String markdownContent) {
        return new MarkdownBuilder().content(markdownContent);
    }

    public static String readMarkdownContent(File file) {
        if (file == null || !file.exists()) {
            return "";
        }

        try {
            return readMarkdownContent(new FileReader(file));
        }
        catch (Exception e) {
            log.error("failed to read markdown content", e);
        }

        return "";
    }

    public static String readMarkdownContent(InputStream inputStream) {
        try {
            return readMarkdownContent(new InputStreamReader(inputStream));
        }
        catch (Exception e) {
            log.error("failed to read markdown content", e);
        }

        return "";
    }

    public static String readMarkdownContent(InputStream inputStream, String charset) {
        if (charset == null || charset.isEmpty()) {
            return readMarkdownContent(new InputStreamReader(inputStream));
        }

        try {
            return readMarkdownContent(new InputStreamReader(inputStream, charset));
        }
        catch (Exception e) {
            log.error("failed to read markdown content", e);
        }

        return "";
    }

    public static String readMarkdownContent(InputStreamReader inputStreamReader) {
        try (BufferedReader reader = new BufferedReader(inputStreamReader)) {
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
                sb.append(System.lineSeparator());
            }
            return sb.toString();
        }
        catch (IOException e) {
            log.error("failed to read markdown content", e);
        }

        return "";
    }

    public static class MarkdownBuilder {
        private String content;

        private MutableDataSet options;

        private AttributeProviderFactory attributeProviderFactory;

        private AttributeProvider attributeProvider;

        private MarkdownBuilder content(String content) {
            this.content = content;
            return this;
        }

        public MarkdownBuilder options(MutableDataSet options) {
            this.options = options;
            return this;
        }

        public MarkdownBuilder attributeProviderFactory(AttributeProviderFactory attributeProviderFactory) {
            this.attributeProviderFactory = attributeProviderFactory;
            return this;
        }

        public MarkdownBuilder attributeProvider(AttributeProvider attributeProvider) {
            this.attributeProvider = attributeProvider;
            return this;
        }

        public MarkdownBuilder printContent() {
            System.out.println(content);
            return this;
        }

        public boolean isMarkdown() {
            if (content == null || content.trim()
                                          .isEmpty()) {
                return false;
            }

            final Document document = this.buildDocument();

            return hasMarkdownNodes(document);
        }

        public Document buildDocument() {
            Parser parser = Parser.builder(this.getOptionsOrDefault())
                                  .build();

            return parser.parse(content);
        }

        public String buildHtmlContent() {
            return this.wrapperHtml(this.getHtmlRenderer()
                                        .render(this.buildDocument()));
        }

        public String buildRawHtmlContent() {
            return this.getHtmlRenderer()
                       .render(this.buildDocument());
        }

        public String buildRawHtmlIfMarkdown() {
            if (this.isMarkdown()) {
                return this.buildRawHtmlContent();
            }

            return content;
        }

        public String buildHtmlIfMarkdown() {
            if (this.isMarkdown()) {
                return this.buildHtmlContent();
            }

            return content;
        }

        private HtmlRenderer getHtmlRenderer() {
            final HtmlRenderer.Builder builder = HtmlRenderer.builder(getOptionsOrDefault());

            if (attributeProviderFactory != null) {
                builder.attributeProviderFactory(attributeProviderFactory);
            }

            if (attributeProviderFactory == null && attributeProvider != null) {
                final IndependentAttributeProviderFactory independentAttributeProviderFactory = new IndependentAttributeProviderFactory() {
                    @Override
                    public @NotNull AttributeProvider apply(@NotNull LinkResolverContext linkResolverContext) {
                        return attributeProvider;
                    }
                };
                builder.attributeProviderFactory(independentAttributeProviderFactory);
            }

            return builder.build();
        }

        private MutableDataSet getOptionsOrDefault() {
            if (options == null) {
                return this.defaultOptions();
            }
            else {
                return options;
            }
        }

        private MutableDataSet defaultOptions() {
            MutableDataSet options = new MutableDataSet();
            // 啟用表格擴展,支持 Markdown 表格語法
            options.set(Parser.EXTENSIONS, Collections.singletonList(TablesExtension.create()));
            // 禁用跨列
            options.set(TablesExtension.COLUMN_SPANS, false);
            // 表頭固定為 1 行
            options.set(TablesExtension.MIN_HEADER_ROWS, 1);
            options.set(TablesExtension.MAX_HEADER_ROWS, 1);
            // 自動補全缺失列、丟棄多余列
            options.set(TablesExtension.APPEND_MISSING_COLUMNS, true);
            options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true);
            return options;
        }

        private String wrapperHtml(String htmlContent) {
            org.jsoup.nodes.Document jsoupDoc = Jsoup.parse(htmlContent);
            jsoupDoc.outputSettings()
                    // 內容輸出時遵循XML語法規(guī)則
                    .syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml)
                    // 內容轉義時遵循xhtml規(guī)范
                    .escapeMode(Entities.EscapeMode.xhtml)
                    // 禁用格式化輸出
                    .prettyPrint(false);
            return jsoupDoc.html();
        }

        /**
         * 檢查 AST 中是否存在 Markdown 特有節(jié)點(非純文本段落)
         */
        private static boolean hasMarkdownNodes(Node node) {
            if (node == null) {
                return false;
            }

            // 判斷當前節(jié)點是否為 Markdown 特有節(jié)點(非純文本)
            if (isMarkdownSpecificNode(node)) {
                return true;
            }

            // 遞歸檢查子節(jié)點
            Node child = node.getFirstChild();
            while (child != null) {
                if (hasMarkdownNodes(child)) {
                    return true;
                }
                child = child.getNext();
            }

            return false;
        }

        /**
         * 判定節(jié)點是否為 Markdown 特有節(jié)點(非純文本段落)
         * 純文本段落(Paragraph)且無任何格式(如鏈接、粗體等)則視為非 Markdown
         */
        private static boolean isMarkdownSpecificNode(Node node) {
            // 標題(# 標題)
            if (node instanceof Heading) {
                return true;
            }
            // 列表(有序/無序)
            if (node instanceof BulletList || node instanceof OrderedList) {
                return true;
            }
            // 列表項
            if (node instanceof ListItem) {
                return true;
            }
            // 鏈接([文本](url))
            if (node instanceof Link) {
                return true;
            }
            // 圖片(![alt](url))
            if (node instanceof Image) {
                return true;
            }
            // 粗體(**文本** 或 __文本__)
            if (node instanceof StrongEmphasis) {
                return true;
            }
            // 斜體(*文本* 或 _文本_)
            if (node instanceof Emphasis) {
                return true;
            }
            // 代碼塊(```代碼```)
            if (node instanceof FencedCodeBlock || node instanceof IndentedCodeBlock) {
                return true;
            }
            // 表格(| 表頭 | ... |)
            if (node instanceof TableBlock) {
                return true;
            }
            // 引用(> 引用內容)
            if (node instanceof BlockQuote) {
                return true;
            }
            // 水平線(--- 或 ***)
            if (node instanceof ThematicBreak) {
                return true;
            }

            // 段落節(jié)點需進一步檢查是否包含 inline 格式(如粗體、鏈接等)
            if (node instanceof Paragraph) {
                return hasInlineMarkdownNodes(node);
            }

            // 其他節(jié)點(如文本節(jié)點)視為非特有
            return false;
        }

        /**
         * 檢查段落中是否包含 inline 格式(如粗體、鏈接等)
         */
        private static boolean hasInlineMarkdownNodes(Node paragraph) {
            Node child = paragraph.getFirstChild();
            while (child != null) {
                // 若段落中包含任何 Markdown  inline 節(jié)點,則視為 Markdown
                if (child instanceof Link || child instanceof Image || child instanceof StrongEmphasis || child instanceof Emphasis || child instanceof Code) {
                    return true;
                }
                child = child.getNext();
            }
            return false;
        }
    }
}

8. 測試示例

import com.vladsch.flexmark.ast.BulletList;
import com.vladsch.flexmark.ast.Heading;
import com.vladsch.flexmark.ast.OrderedList;
import com.vladsch.flexmark.ast.Paragraph;
import com.vladsch.flexmark.ast.Text;
import com.vladsch.flexmark.ext.tables.TableBlock;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * 測試工具類
 *
 * @author ludangxin
 * @since 2025/10/14
 */
@Slf4j
public class Md2htmlTest {
    @Test
    public void given_md_str_then_print_complete_html() {
        final String html = Markdowns.builder("# 簡介 \n hello world~")
                                  // 打印md內容
                                  .printContent()
                                  // 構建html內容, 自動完善html結構
                                  .buildHtmlContent();
        log.info(html);
        // # 簡介
        // hello world~
        //[main] INFO md2html.Md2htmlTest -- <html><head></head><body><h1>簡介</h1>
        //<p>hello world~</p>
        //</body></html>
    }



    @Test
    public void given_md_str_then_print_raw_html() {
        final String html = Markdowns.builder("# 簡介 \n hello world~")
                                  // 構建raw html內容
                                  .buildRawHtmlContent();
        log.info(html);
        //[main] INFO md2html.Md2htmlTest -- <h1>簡介</h1>
        //<p>hello world~</p>
    }

    @Test
    public void given_md_file_then_print_raw_html() {
        final String html = Markdowns.builder(new File("src/test/resources/test.md"))
                                  // 構建raw html內容
                                  .buildRawHtmlContent();
        log.info(html);
        //[main] INFO md2html.Md2htmlTest -- <h2>嘉文四世</h2>
        //<blockquote>
        //<p>德瑪西亞</p>
        //</blockquote>
        //<p><strong>給我找些更強的敵人!</strong></p>
        //<table>
        //<thead>
        //<tr><th>列1</th><th>列2</th></tr>
        //</thead>
        //<tbody>
        //<tr><td>數據1</td><td>數據2</td></tr>
        //</tbody>
        //</table>
    }

    @Test
    @SneakyThrows
    public void given_md_stream_then_print_complete_html() {
        final InputStream fileInputStream = Files.newInputStream(Paths.get("src/test/resources/test.md"));
        final String html = Markdowns.builder(fileInputStream)
                                     // 構建html內容
                                     .buildHtmlContent();
        log.info(html);
        //[main] INFO md2html.Md2htmlTest -- <html><head></head><body><h2>嘉文四世</h2>
        //<blockquote>
        //<p>德瑪西亞</p>
        //</blockquote>
        //<p><strong>給我找些更強的敵人!</strong></p>
        //<table>
        //<thead>
        //<tr><th>列1</th><th>列2</th></tr>
        //</thead>
        //<tbody>
        //<tr><td>數據1</td><td>數據2</td></tr>
        //</tbody>
        //</table>
        //</body></html>
    }

    @Test
    public void given_non_md_content_then_print_complete_html() {
        // 輸入非markdown語法的內容
        final String html = Markdowns.builder("hello world~")
                                     // 構建html內容 (如果內容是md語法則轉換為html, 如不不是 則原樣輸出)
                                     .buildHtmlIfMarkdown();
        // 輸入非markdown語法的內容
        final String html2 = Markdowns.builder("## hello world~")
                                     // 構建html內容 (如果內容是md語法則轉換為html, 如不不是 則原樣輸出)
                                     .buildHtmlIfMarkdown();
        log.info(html);
        //[main] INFO md2html.Md2htmlTest -- hello world~
        log.info(html2);
        //[main] INFO md2html.Md2htmlTest -- <html><head></head><body><h2>hello world~</h2>
    }

    @Test
    @SneakyThrows
    public void given_md_stream_and_attr_provider_then_print_raw_html() {
        final InputStream fileInputStream = Files.newInputStream(Paths.get("src/test/resources/test.md"));
        final String html = Markdowns.builder(fileInputStream)
                        .attributeProvider((node, attributablePart, attributes) -> {
                            // 標題
                            if (node instanceof Heading) {
                                Heading heading = (Heading) node;
                                attributes.addValue("class", "heading" + heading.getLevel());
                            }

                            // 正文
                            if (node instanceof Text) {
                                attributes.addValue("class", "Normal");
                            }

                            // 段落
                            if (node instanceof Paragraph) {
                                attributes.addValue("class", "paragraph");
                            }

                            // 無序列表
                            if (node instanceof BulletList) {
                                attributes.addValue("class", "bulletList");
                            }

                            // 有序列表
                            if (node instanceof OrderedList) {
                                attributes.addValue("class", "bulletList");
                            }

                            // 表格
                            if (node instanceof TableBlock) {
                                attributes.addValue("class", "tableBlock");
                            }
                        })
                        .buildRawHtmlContent();
        log.info(html);
        //[main] INFO md2html.Md2htmlTest -- <h2 class="heading2">嘉文四世</h2>
        //<blockquote>
        //<p class="paragraph">德瑪西亞</p>
        //</blockquote>
        //<p class="paragraph"><strong>給我找些更強的敵人!</strong></p>
        //<table class="tableBlock">
        //<thead>
        //<tr><th>列1</th><th>列2</th></tr>
        //</thead>
        //<tbody>
        //<tr><td>數據1</td><td>數據2</td></tr>
        //</tbody>
        //</table>
    }
}

9.小結

本章使用flexmarkmarkdown內容轉換為html內容, 并介紹了其高級的配置功能和使用jsoup完善html結構,最后封裝鏈式調用的工具類和對應的單元測試代碼, 能夠方便的將各種形式的markdown內容轉換為html內容, 下一章將介紹將html轉換為word內容

源碼

測試過程中的代碼已全部上傳至github, 歡迎點贊收藏 倉庫地址: https://github.com/ludangxin/markdown2html

到此這篇關于Java實現將markdown轉換為html的文章就介紹到這了,更多相關Java markdown轉html內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java實現簡單抽獎功能界面

    Java實現簡單抽獎功能界面

    這篇文章主要為大家詳細介紹了Java實現簡單抽獎功能界面,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • 探討Java語言中那些修飾符

    探討Java語言中那些修飾符

    在java中常見的修飾符有:abstract(抽象的)、static(靜態(tài)的)、public(公共的)、protected(受保護的)、private(私有的)、synchronized(同步的)、native(本地的)、transient(暫時的)、volatile(易失的)、final(不可改變的)。對java語言修飾符感興趣的朋友一起看看吧
    2016-11-11
  • Java調用高德地圖API根據詳細地址獲取經緯度詳細教程

    Java調用高德地圖API根據詳細地址獲取經緯度詳細教程

    寫了一個經緯度相關的工具,分享給有需求的小伙伴們,下面這篇文章主要給大家介紹了關于Java調用高德地圖API根據詳細地址獲取經緯度,文中通過圖文以及代碼介紹的非常詳細,需要的朋友可以參考下
    2024-04-04
  • Spring?Boot?Jwts?Token生成方法示例

    Spring?Boot?Jwts?Token生成方法示例

    這篇文章主要為大家介紹了Spring?Boot?Jwts?Token生成方法示例,非適合java初學者,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • 子線程任務發(fā)生異常時主線程事務回滾示例過程

    子線程任務發(fā)生異常時主線程事務回滾示例過程

    這篇文章主要為大家介紹了子線程任務發(fā)生了異常時主線程事務如何回滾的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-03-03
  • SpringBoot2.x配置多數據源方式

    SpringBoot2.x配置多數據源方式

    這篇文章主要介紹了SpringBoot2.x配置多數據源方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • java+selenium實現自動化操作瀏覽器

    java+selenium實現自動化操作瀏覽器

    在Web自動化的操作中,我們通常需要使用一些方法來操作瀏覽器,這篇文章主要來和大家介紹一下在自動化測試的時候,我們常見的一些瀏覽器操作有哪些,希望對大家有一定的幫助
    2025-05-05
  • SpringBoot中的@EnableAutoConfiguration注解解析

    SpringBoot中的@EnableAutoConfiguration注解解析

    這篇文章主要介紹了SpringBoot中的@EnableAutoConfiguration注解解析,@EnableAutoConfiguration也是借助@Import的幫助,將所有符合自動配置條件的bean定義注冊到IoC容器,需要的朋友可以參考下
    2023-09-09
  • 深入理解JAVA基礎類庫中對象Object類

    深入理解JAVA基礎類庫中對象Object類

    Object類是一個特殊的類,是所有類的父類,如果一個類沒有用extends明確指出繼承于某個類,那么它默認繼承Object類。這里主要總結Object類中的兩個:toString()與equals()方法
    2021-09-09
  • 查看本地啟動SpringBoot的本地端口號的幾種方式

    查看本地啟動SpringBoot的本地端口號的幾種方式

    這篇文章主要介紹了查看本地啟動SpringBoot的本地端口號的幾種方式,文中通過代碼示例講解的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下
    2024-10-10

最新評論

安仁县| 荣昌县| 商河县| 宁蒗| 岳阳市| 隆化县| 东辽县| 仙桃市| 镇雄县| 舟山市| 遵义县| 炎陵县| 南昌县| 尉氏县| 上杭县| 太谷县| 沧州市| 台南市| 塘沽区| 泾川县| 永寿县| 安多县| 定日县| 新密市| 临西县| 万盛区| 长葛市| 屏边| 炎陵县| 乌拉特前旗| 屏东县| 仁布县| 松阳县| 习水县| 闻喜县| 宁化县| 阜宁县| 措勤县| 望都县| 西丰县| 鹿邑县|