DITAのid

DITAのid属性についてはどうも誤解があるようです.
 
例えば、topicのファイルをWindowsファイルシステム上でコピーして別の名前をつけXMetaLなどのXMLエディタで開いて保存してもidがつけ換わってくれない.そもそもtopicのファイルが違うのだからtopicのidがファイルをまたがってユニークである必要はないのではないか?などなど
 
実際DITAはDocBookなんかと違って、はじめからトピックベースで分散オーサリングする前提ですから、idの問題は重要です.DocBookはルートのset要素をトップレベルにしてあらゆるid参照はユニークでなければ成り立ちません.
 
DITAの場合DTDを見てみるとわかりますが、idの性格が最初から違うのです.topicやmapのidはまさにID属性です.でもtopic中の下位要素のidはNMTOKEN属性です.これは何を言っているかというと、
 
1.topicやmapのidはグローバルにユニークでなければならない.
2.topic中の下位要素のidはそのtopicの中でユニークでなければならない.
 
ということです.このことは、下記のDITA1.2の仕様に書いてあります.
 
 
驚くべきことに、topicがネストしていた場合、idはその個々のtopic内でユニークであればよいのです.ですから実際問題パーサーを通してもバリデーションしても重複したidはエラーにならないでしょう.エラーになるのは、ID属性がついているtopic/@idが重複していたときだけです.(バリデーションはtopicのファイル単位に行われるので...)
 
さて最初の話に戻りますが、一般にXMLエディタは新規にDITAインスタンスを作るとき例えばtopic/@idに自動的にid値を生成してくれます.しかし既存のファイルを開いて保存するときidを書き換えることはまずないと思います.何故って、単独でtopicを開いただけでは、そのファイルがいったいどこからconrefされているかまったくわからないからです.もしエディタがconrefされているtopicのidを勝手に書き換えたら大混乱に陥るでしょう.
 
では、ファイルをまたがってユニークである必要があるのかどうかという問題になりますが、これは先ほどのDITAの仕様からすれば答えはYesなのですが、実際にidが重複しているtopicをmapから参照してDITA Open ToolkitでPDFに落としてもエラーは出ません.
 
私はここには重要な問題が含まれていると思っています.一般的に考えれば、PDFに落とすのですから、topicはマージされて一つのファイルになります.そうればファイル名という概念はなくなってtopic/@idが使われてしかるべきなのですが、DITA-OTのTopicMergeタスクは実に「寛大」です.なんとidが重複していても、というより入力topicのidを信じていないで、新たにidとして"unique_N"(Nは番号1..)を生成してくれてしまうのです.なので、これがXSL-FOに落ちてFormatterを通しても、このTopicMergeが自動生成してくれたidを使っている限りはXSL-FOの中のtopicのid重複のエラーは出ないのです.
 
例えば
 
<task id="task_1BB5113EB8094400BAF5714700AD94FF">
はTopicMerge後の中間ファイルでは
 
<task oid="task_1BB5113EB8094400BAF5714700AD94FF" id="unique_1" xtrc="task:1">
になってしまいます.すなわち元のidとしては"unique_N"が使われ、元のidは@oidとして保存されます.
 
ですからCMSなんか使わないでローカルのファイルベースでやっているお客さんはなんでidなんてユニークにしなきゃならないのかと不思議に思うのも当然なのかもしれません.
 
でもこのアーキテクチャには、その先に進めない致命的な欠陥が含まれています.たとえば、これはCMSを使っているお客様ですが、10冊分を超えるマニュアルをDITAでオーサリングしてPDFにしている例があります.ソフトウェアのマニュアルですが、その性格上あるPDFを見ていて、他の分冊のPDFを参照する必要性が出てくる場合があります.そのようなとき、reltableでrelated-linksを作って、PDFからPDFへリンクする機能を実現しています.この時に使うのがPDF名+topic/@idなのです.TopicMergeは、少なくともそのbookmap内でユニークな"unique_N"というidをtopicに振ってくれますが、これではこのidをPDFからエキスポートして他からリンクするようにしたいと思ってもidの名前が何のtopicに対応しているのかはさっぱりわかりません.つまりTopicMergeの生成したidはPDF間のリンクにはまったく使えないのです.
 
ここでtopic/@idをグローバルにユニークにするということが必須要件としてうかび上がります.このお客様はCMSがtopicにオブジェクト名としてGUIDを振って、topic/@idもその値になります.ですからさきほどの中間ファイルで"unique_N"の代わりに@oidを使えば簡単にPDFのリンクは実現できます.(GUIDを書かなけりゃならないので@hrefのオーサリングはちょっと大変でしょうが)
 
もしローカルなファイルシステムでDITAをやっておられて、平気でtopic/@idに重複した値を設定しておられるようでしたら、よくその先の先を考えた方が良いのではないかと思います.スタンダードなDITA-OTの実装が必ずしも正解ではありません.