<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      1. markdown轉word 第一步: markdown轉html

      1. 簡介

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

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

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

      2. 環境信息

      為了兼容更多的場景, 所以并沒有用一些高版本的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) {
              // 創建配置集
              MutableDataSet options = new MutableDataSet();
              // 創建解析器和渲染器
              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進行優化

      1. 添加對應的坐標

        <jsoup.version>1.17.2</jsoup.version>
        
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>${jsoup.version}</version>
        </dependency>
        
      2. 完善html結構

        public static String wrapperHtml(String htmlContent) {
            org.jsoup.nodes.Document jsoupDoc = Jsoup.parse(htmlContent);
            jsoupDoc.outputSettings()
                // 內容輸出時遵循XML語法規則
                .syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml)
                // 內容轉義時遵循xhtml規范
                .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) {
              // 創建配置集
              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);
              // 創建解析器和渲染器
              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語法規則
                      .syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml)
                      // 內容轉義時遵循xhtml規范
                      .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語法規則
                          .syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml)
                          // 內容轉義時遵循xhtml規范
                          .escapeMode(Entities.EscapeMode.xhtml)
                          // 禁用格式化輸出
                          .prettyPrint(false);
                  return jsoupDoc.html();
              }
      
              /**
               * 檢查 AST 中是否存在 Markdown 特有節點(非純文本段落)
               */
              private static boolean hasMarkdownNodes(Node node) {
                  if (node == null) {
                      return false;
                  }
      
                  // 判斷當前節點是否為 Markdown 特有節點(非純文本)
                  if (isMarkdownSpecificNode(node)) {
                      return true;
                  }
      
                  // 遞歸檢查子節點
                  Node child = node.getFirstChild();
                  while (child != null) {
                      if (hasMarkdownNodes(child)) {
                          return true;
                      }
                      child = child.getNext();
                  }
      
                  return false;
              }
      
              /**
               * 判定節點是否為 Markdown 特有節點(非純文本段落)
               * 純文本段落(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;
                  }
      
                  // 段落節點需進一步檢查是否包含 inline 格式(如粗體、鏈接等)
                  if (node instanceof Paragraph) {
                      return hasInlineMarkdownNodes(node);
                  }
      
                  // 其他節點(如文本節點)視為非特有
                  return false;
              }
      
              /**
               * 檢查段落中是否包含 inline 格式(如粗體、鏈接等)
               */
              private static boolean hasInlineMarkdownNodes(Node paragraph) {
                  Node child = paragraph.getFirstChild();
                  while (child != null) {
                      // 若段落中包含任何 Markdown  inline 節點,則視為 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內容

      10. 源碼

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

      posted @ 2025-11-04 20:27  張鐵牛  閱讀(45)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日韩一欧美内射在线观看| 亚洲欧美激情在线一区| 国产欧美日韩高清在线不卡| 亚洲精品一区二区三区免| AV最新高清无码专区| 高级艳妇交换俱乐部小说| 亚洲国产成人资源在线| 一区二区三区岛国av毛片| 日韩中文字幕国产精品| 亚洲精品麻豆一二三区| 国产网友愉拍精品视频手机| 国产精品无遮挡一区二区| 久久亚洲中文字幕伊人久久大| 国产精品日韩av在线播放 | 国产精品免费看久久久| 国产又爽又大又黄a片| 精品无码一区在线观看| 午夜激情福利在线免费看| 一区二区三区鲁丝不卡| 2021亚洲爆乳无码专区| 成人激情视频一区二区三区| 一区二区不卡99精品日韩| 久久精品国产亚洲av电影 | 日本一卡2卡3卡四卡精品网站| 亚洲岛国av一区二区| 忘忧草www日本韩国| 2019亚洲午夜无码天堂| 国产精品亚洲аv无码播放| 人妻少妇精品久久 | 男女性高爱潮免费网站| 精品国产久一区二区三区| 欧美 喷水 xxxx| 国产成人无码免费视频在线| 69精品丰满人妻无码视频a片| 日韩人妻系列无码专区| 久久99精品久久久久久9 | 黄色大全免费看国产精品| 国产亚洲精品成人av在线| 99在线精品免费视频| 久久久久久人妻一区精品| 亚洲码亚洲码天堂码三区|