niszetの日記

細かい情報を載せていくブログ

(Pandoc)PandocのODT出力はシンタックスハイライト未対応

マニュアルに書いてあるけど実際やってみてダメなのを確認。

docx出力では出来るがODT出力ではできないことのひとつに、シンタックスハイライトの対応があります。ODT出力では未対応。

マニュアルのシンタックスハイライトの箇所、

pandoc.org

より引用。対応する形式は下記の通り。

 Currently highlighting is supported only for HTML, EPUB, Docx, Ms, and LaTeX/PDF output. 

実際にPandoc 2.10.1 で確認しましたが未対応でした。

ODT文書を解凍し、内部のcontent.xmlの中も確認しましたが、タグも埋め込まれていないのでODTのテンプレートのスタイルが対応していないというレベルではなく、ファイルとしてハイライト用の情報が入っていないということになりますね。つまり外部のファイルをいじって対応はできない、という事です。

OSTファイルのスタイルが対応していないだけであれば、テンプレート側をいじれば対応も可能となるのですが…。

とりあえず、現状はそうだということで。いずれは対応するかもしれませんね(需要次第でしょう)

(Pandoc)ODT形式は改ページ挿入のためのスタイルの指定が必要。

段々わかってきましたね…。

ODT形式は基本的に全てスタイルでやってしまおうという感じがありますが、改ページも改ページを指定したスタイルを使うことで実現しているようです。

PandocのpagebreakのLuaフィルタを使うことで、改ページを簡単に挿入できることを紹介しました。

niszet.hatenablog.com

このフィルタのREADMEを見ればわかりますが、ODT形式の場合は改ページを指定したスタイル、Pagebreakが必要です。

github.com

このスタイル名は任意のものに置き換えが可能で、Pandocに渡す変数、newpage_odt_style を設定するか環境変数 PANDOC_NEWPAGE_ODT_STYLE によって指定が可能とのこと。実際に試して置き換えがされていました。raw記法を使用して直接埋め込むよりはこのフィルタと変数を使用した方が変更容易になってよいでしょう。

Pandocにパラメータを渡す場合、トップレベルに置かないといけないので、インデントはナシで下記のように書きます。

newpage_odt_style: "Heading_20_1"

こうすることで、文中の \newpage がHeading_20_1、つまり見出し1に置き換えることが確認できます(視認性の観点でこのスタイルにしているので、置き換えが出来ることが分かったあとは適当な改ページ用のスタイルを指定するようにしましょう)

スタイルを指定しているのだから、それごとドキュメントにraw記法で埋め込めば出来るのでは?と思うと思いますが、実際やってみましたがコレはダメです。詳細はODFの仕様を見てほしいですが、styleに関連するタグは本文を記述するcontent.xml中のbodyタグでは無効となり、無視されます。

なので、事前準備が必要になりますが、上記の方法で対応するしかないと思います。まぁ、スタイルは自分で作りこんで使うと思うので、もうひと手間かければよい、というだけなので…。

ODTは何でもタグで対応していてすごいなぁと思う一方で、OOXMLというよりはWordが独特すぎるな…という感じがありますね。一長一短ありますが…。

引き続き、ODT関連については調べていきます…。

ODT形式のzipがちょっと特殊なので気を付けること…

根本的な解決をまだしていない…。

LibreOffice6.0のころから、下記のページにあるようにODTファイルをunzipしてzipしなおすとLOWで開けないよ~という話があったようです。

ask.libreoffice.org

これは、ドキュメント内のmimetypeというファイルがStoreで他はDeflateでないといけないということから来ているようです。しかし、適当なzip系のツールを使ってうまくこれを制御して再作成することが出来ませんでした。

当面の解決方法として、unzipしてzipする場合はcontent.xmlを修正するケースでしょうから、これを更新したファイルとして対象のzipファイルの中身を入れ替える、という形でコマンドを実行すれば良いわけです。

上記サイトの解答にあるコマンド例を引用すると、

zip -f ./decompresslib/X.odt ./decompresslib/content.xml

という形で、zip -fで対象のodtファイルに対して、修正したファイルを入れ替える形で使います。

PandocはODTファイルを開ける形で生成しているので、当然、無からODTを作る方法はあるわけですが、今はODTのファイルをいじって挙動がどうなるのか?が気になるので後回しとします。

なお、普通にzipで生成すると壊れたODTファイルとなりますが、MS Wordは無理やりこれを開きます。しかし、MS WordはODTファイルを開いてもレイアウトが崩れているわけですが、これをMS Word上で保存…とすると、この壊れたレイアウトがLibreOfficeWriter上で再現します。つまり、レイアウトが書き変わってしまいます。

基本的にはMS WordでODTファイル形式を開いてもそれを保存はしない方が良いでしょう。MS Officeで生成されたODTファイルはLibreOfficeで同じように表示はされるので、その方向だけで使うなら良いとは思いますが…。

PandocのODT形式のTOC出力は「目次と索引の更新」をしないと中身が空になる

対処法?があるかは確認中ですが…。

docx形式の場合、目次はフィールドコードが入ってます。一部抜粋するとこういうタグが…。

<w:fldChar w:fldCharType="begin" w:dirty="true" />
<w:instrText xml:space="preserve">TOC \o &quot;1-3&quot; \h \z \u</w:instrText>
<w:fldChar w:fldCharType="separate" />
<w:fldChar w:fldCharType="end" />

ODT形式の場合は全てがstyleになっているようです。値はひょっとしたらアプリが起動時に更新したり等はあるかもですが、基本的には値がそのまま入っている感じですね。なので、ドキュメント単体でデータとして閉じている、ということになるのかな。docxの場合はMS Wordで開かないとフィールドコード部分に実の値が入ってなくても良いので(開いた後に保存したら値入るかも…未確認)

ということで、原理的?にODT形式の場合はLOWで開いて更新をかける必要がありそうです。

が、これは面倒くさいので、LOのAPIで何とかならないだろうか…?と考えています。これがRのパッケージとして作れれば、作成後に更新をかけることも可能…(?)

APIは6.4のものになってるので、7.0はまだなのかな…。とりあえず、取っ掛かりとして可能かどうかは見れそうなのでちょっと見ておきますか…。

api.libreoffice.org

追記

K4氏に最近この話題なかった?と言われてちょっと確認しましたが、

groups.google.com

これのリンク先のissueの最後の方、

github.com

が関連する話題ですが、LibreOffice側も認識はしているけど自動で更新はしていない状態が15年?ということなので、LibreOffice本体がこの機能を実装するというのはちょっと期待できないかな、という感じですね。

9月の目標

先月は読書量は増えたが、手を動かす時間が減っていたので今月は手を動かす方を重視したい。

今月は忘れずに目標を立てる。

技術同人誌

  • ODTについて書く。RMarkdownでODTを作ろう、かな?
  • docxについて書く。スタイルを設定して書く、という話。
  • Rのパッケージ、numberingxを作る…?numbering.xmlの仕様がわからないのでそこから…。
  • ODT向けのパッケージも作る
    • officer likeなので、librerみたいな名前の予定。

生活

  • 引っ越しをおおむね完了させたい
  • 観念して就活をする…

読書

  • とりあえず週1冊、計4冊程度を目標に。
    • Voyage, レガシーコードを優先?あと2冊何をやるか…。

Haskell

  • Pandocのコード読みを始めたので、これを足掛かりにやっていく。

ひとまずこんな感じ。今月はとにかく手を動かすことを厭わずやっていきたいです。

(Haskell)Pandocコード読み: make-reference-files.hs

とりあえずわかるところを増やしていく。

今日読んでいるのはコレ。

github.com

コレはreference.docxなどのテンプレート(正確にはtemplateは別にあるので、referenceと呼んだ方が良さそうだが)を作るためのHaskellのコード。

これは単体で実行できる(mainがある)ので、これを単体で実行しようと思って詰まったのでメモ。

まず、stack ghc make-reference-files.hsとすると、Codec.Archive.Zipなどないと言われる。このモジュール?の説明は下記にある。

hackage.haskell.org

jgm製だったとは…。じゃあってことでstack ghci --package Codec.Archive.Zipってすると怒られる。

正しくは、stack ghci --package zip-archiveである。モジュール名はimportするときの名前とは関係ないのねぇ…。

その後、ビルドでき、実行ファイルが生成されたのでこれを実行すればzip化されたファイルが確認できた。

さて、これで生成されたzipファイルは予想されている形式になっているだろうか…。要確認である…。

いつの間にかrmarkdownでpagebreakのlua filterが使われていたので簡単に紹介する。

各ファイル形式に対応している。

Pandocは、内部的にはファイルを読み込むReaderと書き出すWriterに機能が分けられており、Readerで読んだ文書は内部的にはPandoc's ASTというPandocが扱いやすくするためのデータ構造に一旦データを持ち直します。この中間データに対して処理を加えることで、出力するファイルに色々と操作をする仕組みとしてフィルタがあり、中でもLua言語で書かれたLua filterは最近のPandocでは推しの機能のひとつです。

PandocにはLua filterのリポジトリがあり、色々なユーザから便利なフィルタが提供されています。ライセンスの内容を読み、自分の用途に合わせて使うと良いでしょう。また、自分でこれは良いものが出来たと思ったらリポジトリに追加してもらえないか聞いてみるのも良いでしょう(自分も追加してもらおうと思っていたけど面倒くさくて放置していたらどこに置いたかすら忘れてしまった…)

今回の改ページフィルタもこのリポジトリに納められています(rmarkdownパッケージに内包されているので、こちらのリポジトリのバージョンが上がってもrmarkdownパッケージ内のフィルタは自動的には後進されないので注意…と言ってもあまり変更はないと思うのでヨシ!)

github.com

改ページフィルタの使い方はREADMEを読めばわかりますが、\newpageだけ書かれた段落を入れることで、各出力形式に対応した改ページのコードが生成されて埋め込まれます。\newpageの記述のある行の前後には空の行を入れておきましょう(フィルタのREADMEのとおりですが)

また、RMarkdown Cookbookにも書いてありましたので、こちらもあわせて参考にしてください。

bookdown.org

唯一、ODT形式での出力だけは注意点があるのでそれはまた別途記事に残します。ひとまずここでは紹介だけ。

改ページフィルタは便利なので、独自実装するくらいなら素直にこれを使いましょう。私も独自実装持ってましたが、今後はこれを使っていきます。