KDP(電子出版)のメモ 急急如律令

Amazon Kindleダイレクト・パブリッシングでの電子出版や電子書籍の作成販売について、文章やイラストの作成や編集方法について書いています。

HTMLのパーサーをChatGPTに書かせてみた

 JavaよりJSのほうが慣れているので、JSで書いてからJavaに置き換えることが多いので、二回書く必要が生じている。そこでJSからJavaをChatGPTにやってもらおうと思った。実際にやってみた問題点など。

 ChatGPTに「下記のコードをJavaに書き換えて」で出力されたが思っていたのと違ったので、「下記のコードをJsoupのライブラリを使ったJavaに書き換えて」と直した。

下記のコードをJsoupのライブラリを使ったJavaに書き換えて

    for (let i = 0; i < ruby.childNodes.length; i++) {

        switch (ruby.childNodes[i].nodeName) {
            case '#text':
                bw = bw + '|' + ruby.childNodes[i].textContent
                break;
            case 'RP':
                break;
            case 'RT':
                bw = bw + '《' + ruby.childNodes[i].textContent + '》'
                break;
            case 'RB':
                bw = bw + '|' + ruby.childNodes[i].textContent
                break;
            default:
                console.log("未定義");
        }


    }

ChatGPTの出力したコードの問題点はタグが大文字のままなので小文字にしないと動作しない。あと、childNode instanceof ElementでElementに限定しているので、TextNodeが取得できなかった。ChatGPTは便利だけどなんか嵌り方が余計難しくしている感じがある。でも、結局のところ時短にはなったのでは。

import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.select.NodeFilter;
import org.jsoup.select.NodeTraversor;

// JsoupのDocumentオブジェクトとルビ要素を仮定
Document doc = ...; // ドキュメントを取得するコードを追加する必要があります
Element ruby = ...; // ルビ要素を取得するコードを追加する必要があります

NodeTraversor.traverse(new NodeFilter() {
    @Override
    public FilterResult head(Node node, int depth) {
        if (node instanceof Element) {
            Element element = (Element) node;
            switch (element.nodeName()) {
                case "#text":
                    bw = bw + "|" + element.text();
                    break;
                case "RP":
                    break;
                case "RT":
                    bw = bw + "《" + element.text() + "》";
                    break;
                case "RB":
                    bw = bw + "|" + element.text();
                    break;
                default:
                    System.out.println("未定義");
            }
        }
        return FilterResult.CONTINUE;
    }

    @Override
    public FilterResult tail(Node node, int depth) {
        return FilterResult.CONTINUE;
    }
}, ruby);

stackoverflow.com

rbタグがないルビへ対応するために、ルビへの処理方法を丸ごと変えてみた。 github.com

最近のHTMLタグはrbタグが非推奨になったのでrubyタグのDOMパーサーを書き換えてみた

 HTMLのrubyタグをパースして青空文庫のルビ注記に変換する。ただし、rbタグがあることを前提に作られたHTMLパーサーだとおかしなことになる。AozoraEpub3のrubyタグのパーサー部分を見るとrbタグがあることが前提で書かれている。

 /** ルビを青空ルビにして出力 */
    private void printRuby(BufferedWriter bw, Element ruby) throws IOException
    {
        Elements rb = ruby.getElementsByTag("rb");
        Elements rt = ruby.getElementsByTag("rt");
        if (rb.size() > 0) {
            if (rt.size() > 0) {
                bw.append('|');
                printText(bw, rb.get(0).text());
                bw.append('《');
                printText(bw, rt.get(0).text());
                bw.append('》');
            } else {
                printText(bw, rb.get(0).text());
            }
        }
    }

どういう場合分けがいいのか、rubyタグ内にrbタグがなかったら、textエレメントがあるのかと思ったらnodeNameの#textを見る。ただし、Javaでも同じようには書けなかった。Javaではテキストはテキストノードで、エレメントと別に書かれていた。

ブラウザで可能なテスト要素に書き換えるとモノルビでは対応できてなさそう。ものルビを使っている小説投稿サイトがまずないのだが、rbタグを廃止している傾向がある。

// rubyタグ
let html = "<ruby><rb>漢</rb><rb>字</rb><rp>(</rp><rt>kan</rt><rt>ji</rt><rp>)</rp></ruby>"
let parser = new DOMParser();
let doc = parser.parseFromString(html, "text/html");
ruby=doc.getElementsByTagName("ruby")[0]
rb= ruby.getElementsByTagName("rb")
rt=ruby.getElementsByTagName("rt")
bw=""
if(rb.length){
if(rt.length){
bw=bw + '|' + rb[0].textContent+'《'+rt[0].textContent +'》'

}
else{bw=bw + rb[0].textContent
}
}

モノルビに対応するにはforループを使ってみる

let html = "<ruby><rb>漢</rb><rb>字</rb><rp>(</rp><rt>kan</rt><rt>ji</rt><rp>)</rp></ruby>"
let parser = new DOMParser();
let doc = parser.parseFromString(html, "text/html");
ruby=doc.getElementsByTagName("ruby")[0]
rb= ruby.getElementsByTagName("rb")
rt=ruby.getElementsByTagName("rt")
bw=""
if(rb.length){
if(rt.length){
    for(var i=0; i<rb.length; i++) {
bw=bw + '|' + rb[i].textContent+'《'+rt[i].textContent +'》'
    }
}
else{bw=bw + rb[0].textContent
}

}

次はrbタグがないときの処理

let html =
    "<ruby>漢<rp>(</rp><rt>kan</rt><rp>)</rp>字<rp>(</rp><rt>ji</rt><rp>)</rp></ruby>"
let parser = new DOMParser();
let doc = parser.parseFromString(html, "text/html");
ruby = doc.getElementsByTagName("ruby")[0]
rb = ruby.getElementsByTagName("rb")
rt = ruby.getElementsByTagName("rt")
bw = ""
if (rb.length) {
    if (rt.length) {
        for (let i = 0; i < rb.length; i++) {
            bw = bw + '|' + rb[i].textContent + '《' + rt[i].textContent + '》'
        }
    } else {
        bw = bw + rb[0].textContent
    }
} else {
    for (let i = 0; i < ruby.childNodes.length; i++) {

        switch (ruby.childNodes[i].nodeName) {
            case '#text':
                bw = bw + '|' + ruby.childNodes[i].textContent
                break;
            case 'RP':
                break;
            case 'RT':
                bw = bw + '《' + ruby.childNodes[i].textContent + '》'
                break;
            case 'RB':
                bw = bw + '|' + ruby.childNodes[i].textContent
                break;
            default:
                console.log("未定義");
        }


    }
}

switch caseだけで統一できるかなと思ったんだけど、rb,rb,rt,rtという順番の場合にパースができないので複雑になってしまった。モノルビではなかったらswitch caseだけでよさそう

github.com

モノルビなどrbタグがあったりなかったり、rpタグ内は見ない。

<ruby>漢<rp>(</rp><rt>kan</rt><rp>)</rp>字<rp>(</rp><rt>ji</rt><rp>)</rp> </ruby>
<ruby><rb>漢</rb><rp>(</rp><rt>kan</rt><rp>)</rp><rb>字 </rb><rp>(</rp><rt>ji</rt><rp>)</rp> </ruby>
<ruby>
  <rb>漢</rb><rb>字 </rb><rp>(</rp><rt>kan</rt><rt>ji</rt><rp>)</rp>
</ruby>

developer.mozilla.org

developer.mozilla.org

html2aozoraでrb,rb,rt,rtという順番の場合にパースができてない。パーサーを作るのが難しい。 github.com

キンドルのセールに関するサイトをブログから分離した

 以前は頻繁にこのブログでkindleセールに関する記事を上げていたが管理が面倒になったのでGatsbyJSで作ったサイトに管理を一元化した。メリットとしてはセールが終わったリンクが切れたものをすぐに削除が可能になった。今までは、記事の一括削除が過去ログを検索しながら見つける必要があった。  サイト記事のテンプレート部分をプログラムから出力することにした。MDXとアマゾンアフィリエイトを連携させて表示、その他JSONでデータ管理している。なのでデータ部分を更新したければJSONを更新し、記事内容を変えたければMDXを書き換える。  seoを重視したサイト設計で検索からのサイトへのクリック数は増えたが、PVが増えたとは限らない。このブログもリンク切れが減ったのでサイト自体の評価自体は上がったが、投稿頻度が減ったのでPVが下がったかもしれない。

kyukyunyorituryo.github.io

kyukyunyorituryo.github.io

4月11日から4月17日までキンドル新刊ピックアップ

4月11日発売の本

4月11日発売のそのほかの本kyukyunyorituryo.github.io

4月12日発売の本

魔法使いの嫁 20 (ブシロードコミックス)

魔法使いの嫁 20 (ブシロードコミックス)

Amazon
魔法使いの嫁 断片集 (ブシロードコミックス)

魔法使いの嫁 断片集 (ブシロードコミックス)

Amazon

4月12日発売のそのほかの本kyukyunyorituryo.github.io

4月13日発売の本

4月13日発売のそのほかの本kyukyunyorituryo.github.io

4月14日発売の本

4月14日発売のそのほかの本kyukyunyorituryo.github.io

4月15日発売の本

4月15日発売のそのほかの本kyukyunyorituryo.github.io

4月16日発売の本

4月16日発売のそのほかの本kyukyunyorituryo.github.io

4月17日発売の本

4月17日発売のそのほかの本kyukyunyorituryo.github.io

Java8を入れないとKindle Previewerが動かないのでJava8を入れた

Java8を入れないとKindle Previewerが動かないのでJava8を入れた

Kindle PreviewerがJava8を削除すると動かなくなる、たぶんバックグラウンドで使っているのだろう。なぜ Java8を削除していたかというと、Java8を更新するたびにJava21がコマンドラインから動かなくなるから。どうやら環境変数がJava8を優先して実行されてJava21が動かないようだ。

環境変数の書き換え

 スタートメニューを右クリックしてシステム、ホームの下の入力欄に「詳細設定」と入力 「システムの詳細設定の表示」「環境変数」ボタンをクリック、システム環境変数の「path」を選び「編集」 「C:\Program Files\Eclipse Adoptium\jre-21.0.2.13-hotspot\bin」を選択して「上へ」をクリックして一番上に移動する。「OK」ボタンを押して閉じていく。コマンドラインを再起動してjava -versionを入力してJava21が表示されるかを確認する。JAVA_HOMEの設定が一般的な方法だけど、どっちがいいのやら。

参考 www.scc-kk.co.jp

JAVA_HOMEの設定 www.javadrive.jp