1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

nXMLでXInclude入りDocBook文書を検査する

Last updated at Posted at 2021-05-15

nXMLで1つのXMLファイルに複数のRELAX NGを適用しようとしたけれども、その必要はなかったというお話です。

nXML Mode?

Emacsには nXML mode というXMLのためのメジャーモードがあります。RELAX NGスキーマに従って編集しているXML文書の妥当性を確認してくれたり、補完で候補を出してくれたりして便利です。

追加でスキーマを読み込む

デフォルトで読み込まれるRELAX NGだけでは足りないと思うこともあります。そういったときには、Locating a schema のように、読み込むスキーマを追加することもできます。

DocBook の RELAX NGスキーマファイル

例えばDocBook 5.1文書を編集したいとしましょう。これはデフォルトではnXMLは備えていないので、自分で設定する必要があります。

DocBookはRELAX NGで定義されています(Relaxing with DocBook)。macOSであればHomebrewから入手することもできます。オープンソースソフトウェアのドキュメントはDocBookで書かれているものもあるので、知らないうちに入っていた、ということはありそうです。

$ brew info docbook
docbook: stable 5.1 (bottled)
Standard SGML representation system for technical documents
https://docbook.org/
/usr/local/Cellar/docbook/5.1_1 (199 files, 8.9MB) *
...

$ brew install docbook
...

そして私の環境では、バージョン5.1のコンパクトRELAX NGスキーマファイルは /usr/local/Cellar/docbook/5.1_1/docbook/xml/5.1/schemas/rng/docbook.rnc に置かれました。

スキーマの場所を指定する

スキーマ読み込みのための設定ファイルはXMLによるものです。以下のような内容を適当な場所の適当なファイル名で保存します。今回は ~/.emacs.d/schemas.xml とします。namespace 規則を使用しましたが、他にもXMLファイルにマッチさせるための方法はいくつかあります。

~/.emacs.d/schemas.xml
<?xml version="1.0"?>
<locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0">
  <namespace ns="http://docbook.org/ns/docbook" uri="/usr/local/Cellar/docbook/5.1_1/docbook/xml/5.1/schemas/rng/docbook.rnc"/>
</locatingRules>

nXMLの設定

そして、Emacsの設定ファイルで nXML mode の設定にもこの ~/.emacs.d/schemas.xml について書く必要があります。ここでは leaf.elでは以下のようになります。

~/.emacs.d/init.el
...
(leaf nxml
  :ensure t
  :config
  (eval-after-load "rng-loc"
    '(add-to-list 'rng-schema-locating-files "~/.emacs.d/schemas.xml"))
  :defvar rng-schema-locating-files)
...

また、Customであれば以下のように設定します。これは手で編集するのではなく、M-x customize-variable RET rng-schema-locating-files RETとすればCustomの設定画面が開くので、そこからパスを指定します。

~/.emacs.d/init.el
(custom-set-variables
 ...
 '(rng-schema-locating-files '("~/.emacs.d/schemas.xml"))
 ...

これにて純粋なDocBook5.1文書を快適に編集することができます。

XIncludeしたい

DocBookには programlisting 要素があり、コードブロックを表現することができます。このとき、別のファイルに取り込まれるソースコードを書いておきたいときがあります。
また、文書が長大になってくると、複数のファイルに分割したいと思うことがあります。

XMLで外部ファイルを読み込む方法は主に2つあるのですが、どちらを採用すればよいでしょうか。

DocBook The Definitive Guide (Version 1.5.3 for DocBook 5.1) には以下の記述があります。したがって普段使いではXIncludeによる方法を取るようにしています。

As time passes, the use of DTD-based mechanisms like entities is diminishing. If you have an eye on the future, to the extent that it is practical, it is probably better to use XInclude than entities.

XIncudeのコンパクトRELAX NGスキーマ

XIncludeの規格にはRELAX NGによるスキーマは載っていません。ここではTrangを使って変換することにしました。変換結果は以下です。

~/.emacs.d/schemas/xinclude.rnc
default namespace = "http://www.w3.org/2001/XInclude"
namespace a0 = "http://relaxng.org/ns/compatibility/annotations/1.0"

start |= \include
\include = element include { includeType }
includeType =
  (fallback
   | element * { text }
   | element * { text })*,
  attribute href { xsd:anyURI }?,
  [ a0:defaultValue = "xml" ] attribute parse { parseType }?,
  attribute xpointer { xsd:string }?,
  attribute encoding { xsd:string }?,
  attribute accept { xsd:string }?,
  attribute accept-language { xsd:string }?,
  attribute * { text }
parseType = "xml" | "text"
start |= fallback
fallback = element fallback { fallbackType }
fallbackType =
  (\include
   | element * { text }
   | element * { text })*,
  attribute * { text }

これでRELAX NGファイルの準備が整いました。

複数のRELAX NGを結合したい

前節まででRELAX NGファイルの用意はできましたが、問題はこれを1つのDocBook文書に適用する方法です。nXML modeのマニュアルを読むに、1つの文書に対して1つのスキーマを当てる方法はありますが、1つの文書に対して2つ以上のスキーマを当てる方法については説明がありません(はずです)。

external?

それではRELAX NG的に解決しようとするとどうなるのか。RELAX NG Compact Syntax Tutorialを斜め読みしたところ、 external が良さそうです。2つのRELAX NGスキーマファイル、DocBook用とXInclude用を両方 external で読み込みます。

~/.emacs.d/schemas/docbook_xinclude.rnc
external "/usr/local/Cellar/docbook/5.1_1/docbook/xml/5.1/schemas/rng/docbook.rnc" | external "xinclude.rnc"

スキーマの場所指定もそれにともなって変えておきます。DocBookファイルの編集には先のコンパクトRELAX NGスキーマファイルを使います。

~/.emacs.d/schemas.xml
<?xml version="1.0"?>
<locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0">
  <namespace ns="http://docbook.org/ns/docbook" uri="schemas/docbook_xinclude.rnc"/>
</locatingRules>

結果

これでうまくいきそうではあるのですが、実際にはXIncludeの要素の部分で警告が出ています。DocBookのスキーマ定義では、ある要素の子要素にXIncludeの要素(例えば xi:include 要素、ただし xi はXIncludeの名前空間であるとする)を含む、とは書いてありません。したがってnXML modeは妥当性がないと判断するのでしょう。

それではXIncludeのスキーマ読み込みは効果がないのかというとそうではなく、XInclude要素内の属性については補完もされますし、妥当性の検査もされます。例えば xi:include 要素中の href 属性や parse 属性については補完されますし、妥当であると認められます。

個人的には、XIncludeを使う部分は simpara 要素や literal 要素ほどおびただしいわけではないので、これでもわりと充分だったりします。

XIncludeしたい - その2

実はDocBookが配布しているRELAX NGスキーマにはXIncludeを加味したバージョンも付属しています。いい感じにDocBookとXIncludeが融合されているのでこちらを使いましょう。ディレクトリ名やファイル名にdocbookxiが入っているのが目印です。

展望

素のDocBookでも充分ではありますが、略記や独自の要素で拡張したくなるときがあります。今回はありもので済んでしまいましたが、そうしたカスタマイズを加えたくなったときに、気軽にスキーマやスタイルシートを変更できるようになると良さそうです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?