この記事の「サンプル」で扱ったJATS XML文書サンプルを、HTMLに変換してVivliostyleでページ組版してみます。(長い記事です…)
JATS XMLやDITA1をページ組版というと、XSLT2で変換してXSL-FO3やTeXやCSSで組んで…という解説を見かけますが、ここはJavaScriptでDOMを変換してCSSで組みます。つまりフロントエンドの技術でページ組版しようというわけです。
変換はごく単純で、元のJATS XMLの構造を大胆には変えないようにします。やってみると分かることがあって、この気付きが目的です。というわけで、泥臭く進めていきます。
「JATSが分かる…」の薄い本を作ってみましょう!(薄くないw)
手順
前記の記事で、サンプルをダウンロードして展開したところから始めます。Visual Studio Codeやvscode-xmlは、まだ手を付けてなくて大丈夫、後の個々の画像にサイズを設定してみようで使います。
JATS XML文書をHTMLに変換
次のURLのページでJATS XML文書を読み込んでHTMLに変換して、拡張子だけ.htmlに変えたファイルを作り、元のJATS XML文書と同じところに置きます。
この2025_112.xmlを変換して2025_112.htmlを作り…
JATSBOOK_XML
├── 2025_112
│ ├── 2025_112.txt
│ ├── 2025_112.xml
│ └── Graphics
│ …
同じフォルダーに置きます:
JATSBOOK_XML
├── 2025_112
│ ├── 2025_112.html # 変換して追加
│ ├── 2025_112.txt
│ ├── 2025_112.xml
│ └── Graphics
│ …
これをすべてのJATS XMLで繰り返します。
(何度もやるようになったら面倒ですよね)
そうなったら一括変換の仕組みを用意するでしょう(この項、修正しました 2025-07-09)。
例えば、次をダウンロードして:
package.jsonを用意して:
{
"type": "module",
"dependencies": {
"xmldom": "^0.6.0"
}
}
後のVivliostyleを実行するのとは別のJATSBOOK_XMLフォルダー/ディレクトリを用意して、こんな構造にして:
JATSBOOK_XML
├── 2025_112
├── 2025_122
├── 2025_14
├── …
├── index.js
├── j2hN.js
├── lib
│ ├── convert.js
│ └── sed.js
└── package.json
Macなら、次を実行すると楽……なはずです。ご笑覧ください
find ./2025* -type f -name "*.xml" | while read -r f; do
node index.js "$f" > "${f%.xml}.html"
done
変換後にVivliostyleで組版する用のフォルダー/ディレクトリにコピーします。
ちなみに、この変換処理はみなさんのブラウザーで、みなさんのパソコンなどで実行されます。変換プログラムを置いてあるサーバーでではなく、「変換処理がサーバーに集中して重い」みたいな事態にはなりにくいと思います。
1つのHTMLファイルを複製
HTMLファイルを1つ複製します。奥付用です。
後の構成ファイルに合わせて2025_i.htmlを複製することにします…
JATSBOOK_XML
├── …
└── 2025_i
├── 2025_i.html # これを複製
├── 2025_i.txt
├── 2025_i.xml
└── Graphics
こうなります。構成ファイルに合わせて2025_i copy.htmlという名前にしてください。
JATSBOOK_XML
├── …
└── 2025_i
├── 2025_i copy.html # 複製
├── 2025_i.html
├── 2025_i.txt
├── 2025_i.xml
└── Graphics
Vivliostyleをインストール
まだインストールしてなければ、次のページの手順でVivliostyleをインストールします:
構成ファイルvivliostyle.config.jsを用意
Vivliostyleの構成ファイルvivliostyle.config.jsを用意します。これはVivliostyleに、どのファイルをどのように処理するか指示するものです。
vivliostyle.config.jsという名前のファイルを用意して、中身を次のコードとして、JATSBOOK_XMLフォルダー直下に置きます。Qiitaではカーソルをコード領域に持ってくると右上に現れるコピーボタンを押してコピーできます。
module.exports = {
title: 'JATSがわかる 学術情報XML作成の実際',
language: 'ja',
theme: ['https://yamahige.github.io/study/jats2html/vivliostyle/body.css'],
copyAsset: {
includes: [
]
},
author: '学術情報XML推進協議会',
entry: [
// {
// /* 目次 */
// path: "./cover.html",
// theme: ['./body.css', './cover.css'],
// },
{
path: "./2025_i/2025_i.html",
theme: ['https://yamahige.github.io/study/jats2html/vivliostyle/jats_i.css'],
},
{
// path: 'toc-template.html',
theme: ['https://yamahige.github.io/study/jats2html/vivliostyle/toc.css'], // ページ番号を付けるなど
output: 'toc.html',
rel: 'contents',
pageCounterReset: 1,
},
{
path: "./2025_2/2025_2.html",
theme: [
'https://yamahige.github.io/study/jats2html/vivliostyle//body.css',
'https://yamahige.github.io/study/jats2html/vivliostyle/page-reset.css' // ページ番号をリセット
],
},
"./2025_14/2025_14.html",
"./2025_38/2025_38.html",
"./2025_52/2025_52.html",
"./2025_65/2025_65.html",
"./2025_78/2025_78.html",
"./2025_98/2025_98.html",
"./2025_112/2025_112.html",
"./2025_122/2025_122.html",
{
path: "./2025_i/2025_i copy.html",
theme: ['https://yamahige.github.io/study/jats2html/vivliostyle/okuduke.css'],
},
],
output: [
'jatsbook.pdf',
],
toc: {
title: '目次',
htmlPath: 'toc.html',
sectionDepth: 2,
},
workspaceDir: './.vivliostyle',
};
ファイルの構成はこうなります:
JATSBOOK_XML
├── 2025_112
├── 2025_122
├── 2025_14
├── 2025_2
│── 2025_38
├── 2025_52
├── 2025_65
├── 2025_78
├── 2025_98
├── 2025_i
└── vivliostyle.config.js # 追加した構成ファイル
プレビュー
JATSBOOK_XMLフォルダーで、次のコマンドを実行してプレビューします:
$ vivliostyle preview
次のコマンドでjatsbook.pdfという名前のPDFファイルが出力されます:
$ vivliostyle build
考察
変換といっても、ほとんどの要素はそのままスルーしてます。変換結果を左右見比べると分かるでしょう。article-metaといった要素もそのままVivliostyleに入力してます。
以降で、変換について主なポイントを説明します。
や といった文字実体参照と外部実体
JavaScriptのパーサーには、JATS XML文書をHTML文書text/htmlとして読み込ませてます。なぜかというと…
や といった文字実体参照は、HTMLでは宣言せずに使えます。一方、XMLでは宣言が必要です(実体参照といいます)。で、それはJATSのDTDをたどるとisopub.entというファイルで、こんなふうに宣言されてます。
<!ENTITY emsp " " ><!--=em space -->
問題は、JavaScriptのパーサーが、DTDをたどって外部実体を読みに行ってくれないことです。ブラウザーでも、サンプルのJATS XML文書を表示しようとすると次のエラーになります:
This page contains the following errors:
error on line 63 at column 26: Entity 'emsp' not defined
error on line 74 at column 180: Entity 'ldquo' not defined
error on line 79 at column 51: Entity 'nbsp' not defined
error on line 92 at column 57: Entity 'nbsp' not defined
error on line 104 at column 26: Entity 'emsp' not defined
いやいや、「not defined」って、DTD指定してるのに……困りました。
HTML文書として読み込ませれば、この問題は起きません。このために変換後のファイルの拡張子を.htmlにしてます。これで大丈夫なのか……
JATS XMLの名前空間
「後方互換のために、JATS自身には名前空間の記法を使わなくてよい」ことになってるようです。J-STAGEとはJATSのバージョンが異なりますが、次のURLに説明があります。
実際、サンプルのJATS XML文書では、XLinkのxlink:hrefといった導入要素を除いて、JATS XML自身は名前空間を宣言してません。
一方、HTMLも名前空間を使わなくてよいことになってます。そこで、JATS XML文書をHTML文書として読めてしまう……ようです。
HTMLのtitleやbodyと事前の文字列変換
JATSにもbodyやtitleという要素がありますが、HTMLのとは役割が異なります。ブラウザーのDOMParserや、JSDOMが読み込む時点で特別扱いされてしまうので、パーサーで読み込む前に文字列変換で名前を変えます。
前記の変換プログラムでは次のように文字列変換してます:
-
title->jats-title -
body->jats-body
title
JATSのtitleはHTMLのh1〜h6相当、あるいは図表のcaptionの中でも使われてます。
こんな感じ
<sec>
<label>(1)</label>
<title>J-STAGE…</title>
<p>…</p>
<!-- … -->
</sec>
あるいはこう
<fig>
<label>図7.2</label>
<caption>
<title>画面構成</title>
</caption>
<graphic xlink:href="gui.jpg"/>
</fig>
一方、HTMLのtitleは文書中に唯一で特別です。例えば、テキストのみ含めることができて、supなどを含められません。
また、HTMLのtitleは空要素ではありませんが、JATS XML文書には空の<title/>があります。これも事前に文字列変換します。
body
HTMLのbody要素は特別で、パーサーで読み込むとhtml > bodyの配下にhead以外の要素がぶら下がるように構造変換されてしまいます。
JATSのlabel
HTML + CSSなら疑似要素で自動生成するようなテキストが、JATSではlabel要素になっています。前記の例もそうなってます。
箇条書きもこんなふうで、「●」が生成済です:
<list>
<list-item>
<label>●</label>
<p>title要素とbody要素は特別です。</p>
</list-item>
<!-- …… -->
</list>
JATSの画像graphic
JATSの画像はgraphic要素ですが、このままブラウザーなどに渡しても画像は表示されません。変換プログラムでは、パーサーで読み込んだ後、img要素に置き換えてます。
こんなふうに記述されてます:
<graphic xlink:href="photo.jpg"/>
そこで、次のようなCSSが有効ならよいのですが、url()関数内にattr()関数を書けないようで、ダメです。
graphic {
content: url(attr(xlink\:href));
}
/* または */
graphic::after {
content: url(attr(xlink\:href));
}
なお、xml:lang属性など名前空間プレフィックス付きの属性をCSSの属性セレクターに使うときは、abstract[xml\:lang="ja"]などと:を\でエスケープするそうです。
インラインボックスのまとまり
JATSでは、ブロックボックスにまとめたくなるようなインラインボックスが、特にまとまりなく並んでいます。
セクション見出し
セクション番号と見出しが次のような構造になってます:
<sec>
<label>第1章</label>
<title>JATSの歴史</title>
<p>昔々…</p>
<!-- … -->
</sec>
次のように表示したいのですが、labelとtitle(jats-titleに変換されます)がpと同じレベルで並んでいて、まとまってません。
第1章 JATSの歴史
昔々…
このままだと、次の記事の「見出しをrun-inにする」手法を使うことになりますが、扱いにくいので、パーサーで読み込んだ後、jats-title-wrap要素でくくってます。
<sec>
<jats-title-wrap>
<label>第1章</label>
<jats-title>JATSの歴史</jats-title>
</jats-title-wrap>
<p>昔々…</p>
<!-- … -->
</sec>
図表のキャプションも同様です。「図のキャプションは図の下、表は上」にしたくても、label、title、graphicなどと3つに分かれてると、display: flex; flex-direction: column-reverse;などで制御しようとすると困っちゃいますよね。
<fig>
<label>図7.2</label>
<caption>
<title>画面構成</title>
</caption>
<graphic xlink:href="gui.jpg"/>
</fig>
目次生成
Vivliostyleに目次を自動生成してもらうために、title要素(というかjats-title-wrap要素)のままでは目次ができません。h1、h2、h3などの要素を想定しているからです。そこで、トップレベルだけjats-title-wrapをh2に置き換えてます。
奥付
奥付を生成するために、どれかのHTMLファイルを複製します。前記の手順では2025_i copy.htmlとしました。中身は全く同じでファイル名が異なるようにします4。どのファイルでもよいです……つまり、どのファイルにも(章だけでなく)書籍の情報が入ってます。論文でいえば掲載誌の情報です。今回は表紙を作ってませんが、表紙も同じ方法で作れます。
もちろん、DOMを変換して奥付用ファイルを作るワークフローもありでしょう。
画像graphicのサイズ
さて、入手できるJATS XML文書では、画像にサイズがありません。
そこで、Vivliostyleに渡すCSSでは、graphicから変換したimgについて一律に、次のように設定してます:
img {
max-inline-size: 90%;
max-block-size: 60vh;
margin-inline: auto;
}
個々の画像にサイズを設定してみよう
これはページ組版なので、サイズや配置を調整したいですよね。
やってみましょう!
まず、できれば次の記事のように、Visual Studio Code (以下、VSCode)とXML拡張機能(vscode-xml)を用意して、DTDを読み込んでバリデーションできるようにしておきます。できなくてもよいです、テキストエディターでもOKです。
JATS XML文書、例えば./2025_2/2025_2.xml(2025_2.htmlではなく)をVSCodeで開いて、graphic要素を、style属性付きのstyled-content要素で囲みます。
<graphic xlink:href="2025_2_f1.jpg"/>
を、このように編集します。
<styled-content style="inline-size: 50%; float: outside;">
<graphic xlink:href="2025_2_f1.jpg"/>
</styled-content>
画像の幅をページ幅の50%にして外側寄せにするという設定です。
float: outside;はVivliostyleの新しい機能です
編集前は横幅いっぱいだった画像が、半分の幅で外側寄せになってれば成功です。
このようにして、ソースのXML文書で、画像のサイズや配置を調整できます。
styled-content要素とstyle属性
ここで、編集後でも妥当なXML文書であることに注目してください。VSCodeとvscode-xmlを使って編集すると分かります。バリデーションが成功します。
試しに、graphic要素にstyle属性を設定するとエラーになり、ちゃんとバリデートされてることが分かります。styleのところに赤い波線が表示されるのを確認できます。
<graphic xlink:href="2025_2_f1.jpg" style="inline-size: 50%; float: outside;"/>
styled-content要素にstyle属性(XMLでは@styleと表現したりします)を使うのは、JATSが用意している方法です。
ただし、J-STAGEの「XMLフォーマットガイドライン」などにはstyled-contentの記述が見当たらず、使ってよいものかどうか分かりません……
この他に、named-content要素があって、こちらはHTMLのclass属性の用法に似ています。ただし@classはなくて、@content-typeや@specific-useで識別します。
JATSの画像のサイズ設定
JATSで画像にサイズが設定されていなくてもよい事情は、実際に公開されている論文をJ-STAGEで見ると想像できます。どの画像も固定幅の100%で表示するように設定されていて、クリックすると拡大表示されるようになってます。
次のようにして実物を確認できます:
J-STAGEトップページで、「検索条件の詳細設定」から、まず「指定検索」に何か入力します(ここに何か入れないと検索してくれません)。そして「記事属性」で「本文(HTML形式)」をチェックします。見たところ、HTML形式が公開されてるのは医薬系に多いです。例えば「論文タイトル」に「COVID-19」などと入力します。検索結果一覧の画面で、「認証」の「フリー」や「オープンアクセス」をチェックすると無料・会員登録不要で読める論文に絞り込めます5
あるいは「情報管理」という雑誌です。休刊してるのですが、この論文は、すべてフリー& HTML形式で見られるんじゃないでしょうか
https://www.jstage.jst.go.jp/browse/johokanri/-char/ja
いずれも論文一覧の画面で、各論文の「HTML形式で全画面表示」をクリックするか、タイトルをクリックして開いたページの右上の「本文(HTML形式)」をクリックすると、JATS XMLから変換して作ったHTML形式で論文を閲覧できます。
細かいところはやってません
- 著者は奥付に一覧したい。そういった奥付生成はDOMで可能でしょう
- 図のキャプションは下、表キャプションは上にしたい
- 目次の最後の項目の見出しが「序文…」なのはおかしい。そもそも奥付は目次に載せないでしょう
- いまさらですが、XML文書の空白文字や改行は要注意で、整形(prettify)は危険です。何がどのように変換されるのか、整形した方が対比しやすいので、変換プログラムは整形して見せています。実際のワークフローでは整形しないデータを使うべきです。(2025-07-27 追記)
以上です、お疲れ様でした。
CSSの中身は、後でゆっくりご笑覧ください。ここで紹介した手法を使ってます
-
Darwin Information Typing Architecture https://ja.wikipedia.org/wiki/Darwin_Information_Typing_Architecture ↩
-
同じファイルが複数個entryしてるとVivliostyleでエラーになります。 ↩
-
「COVID-19」の結果はフリーやオープンアクセスのものだけですね……という点が、JATS XMLについては重要だったりします。 ↩






