ST_FUNC開発日記

建築構造設計Excelアドイン開発の記録

mdからhtmlの変換 その3

前回の下記の問題点を解決する

  • 単純にそのまま変換するので、ヘッダーとかがない
  • 表が変換されていない
  • 数式が変換されていない
  • ハイパーリンクが機能しない
  • 画像が表示されない。

ヘッダー等の作成

htmlのテンプレートを用意し、bodyのみ置き換えることにする。

簡単なテンプレート

<!DOCTYPE html>
<html lang=ja>
<head>
<meta charset=”utf-8” >
<title>{{TITLE}}</title>
</head>
<body>
{{BODY}}
</body>
</html>

この{{TITLE}}と{{BODY}}をmarkdownから変換したhtmlに置き換えることによって、htmlページを作る。

{{}}はとくに意味はないが、なんとなくdjangoのテンプレートのイメージで作ってみた。

ということでconvert_md_to_html関数の途中に下記を追加

with open("template.html", "r", encoding="utf-8") as template_file:
        template_text: str = template_file.read()
        title: str = os.path.splitext(os.path.basename(input_path))[0]
        html = template_text.replace("{{TITLE}}", title).replace(
            "{{BODY}}", html
        )

表が変換されない

qiita.com

上記記事を参考にするとextensionsでtablesを指定するとよいらしい。

ということで、変換部分を下記の様に修正

    with open(input_path, "r", encoding="utf-8") as md_file:
        md_text = md_file.read()
        html: str = markdown.markdown(md_text, extensions=["tables"])

よし、表は無事に変換されたけど罫線ないな。htmlの表ってデフォルトで罫線なかったっけ?

まあ、あとでcssでも書こう。

数式が変換されない

python-markdown-mathの公式説明を見てみる。

pypi.org

これによるとhtmlにmathjexを使うことを記載

<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js">
</script>

さらに設定を記載

<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  config: ["MMLorHTML.js"],
  jax: ["input/TeX", "output/HTML-CSS", "output/NativeMML"],
  extensions: ["MathMenu.js", "MathZoom.js"]
});
</script>

そしてextensionsにmdx_mathを指定すればよいようだ。

ということで、変換部分を下記の様に修正

    with open(input_path, "r", encoding="utf-8") as md_file:
        md_text = md_file.read()
        html: str = markdown.markdown(
            md_text, extensions=["tables", "mdx_math"]
        )

これで変換をかけてみるとソースを見てみると

<h3>iY:Y軸まわりの断面二次半径</h3>
<p>
<script type="math/tex; mode=display"> iY=\sqrt{\frac{IY}{A}} </script>
</p>

の様になっているので、うまくいったように見えるけど、数式が表示されない。 pythonの変換はうまくいっているはずなので、htmlの問題かな?

chatGPTに相談したら下記のような回答が

あなたの提供したコードでは、MathJaxを使用して数式を表示しようとしていますが、いくつかの問題があります。

  1. MathJaxのスクリプトが正しく読み込まれていない可能性があります。
  2. MathJaxの設定が不足している可能性があります。
  3. 数式を表示するための正しいスクリプト構文を使用していない可能性があります。

以下は修正されたコードです。MathJaxのスクリプトを正しく読み込み、数式を正しく表示するために必要な変更が加えられています。

<head>
略
<script type="text/javascript" async
  src="https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=TeX-MML-AM_CHTML">
</script>
</head>
略

変更点: - MathJaxのスクリプトの読み込み方法を変更しました。

これにより、数式が正しく表示されるはずです。

ということで、template.htmlを下記の様に修正してみた。

<!DOCTYPE html>
<html lang=ja>
<head>
<meta charset=”utf-8” >
<title>{{TITLE}}</title>
<script type="text/javascript" async
  src="https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=TeX-MML-AM_CHTML">
</script>
</head>
<body>
{{BODY}}
</body>
</html>

無事に数式が表示できた。 ・・・と思ったら、インラインの数式($が一つのやつ)が変換できていない。

ドキュメントを見ると下記の設定が必要らしい。

enable_dollar_delimiter=True

どこで設定するんや?ということで、chatGPTさんに聞きながら変換部分を下記のように設定。

    with open(input_path, "r", encoding="utf-8") as md_file:
        md_text = md_file.read()
        html: str = markdown.markdown(
            md_text,
            extensions=["tables", "mdx_math"],
            extension_configs={"mdx_math": {"enable_dollar_delimiter": True}},
        )

これで、インラインの数式も変換できた。

ハイパーリンクが機能しない

htmlを見てみるとリンクがa hrefにはなっているが、リンク先が.mdのままになってしまっている。

なので、リンク先の拡張子だけ変えてあげればいい。 ということで、テンプレート修正に下記を追加

html = html.replace('.md"', '.html"')

画像が表示されない

これは、画像はhtmlフォルダ内にコピーされないことが原因であるようだ。

ということでコピーするルーチンを足してあげる。

mdを再帰的に取得するglobのコードを参考に画像をコピーしていく。

IMAGE_EXTENSIONS = (
        ".gif",
        ".jpg",
        ".png",
        ".svg",
    )
    for image_extension in IMAGE_EXTENSIONS:
        for image_file_path in glob.glob(
            f"{input_folder}/**/*{image_extension}", recursive=True
        ):
            relative_path = os.path.relpath(image_file_path, input_folder)
            output_path = os.path.join(output_folder, relative_path)
            output_dir = os.path.dirname(output_path)
            if not os.path.exists(output_dir):
                os.makedirs(output_dir)
            shutil.copy2(image_file_path, output_path)
            print(f"コピー完了: {image_file_path} -> {output_path}")

copy2って適当なネーミングだな。

これで画像も表示されるようになった。

md_to_htmlの更新、htmlテンプレートの作成 · st-func/st_func_docs@7e3fc87 · GitHub