idの重複(3)

話しのついでにtopicの参照の重複について書いておきます.(もしかしたら以前書いたかもしれません)いろいろなお客様に話を伺っても、ひとつの文書の中で同じtopicを二回以上使用する(マップから参照する)ということは「絶対にない」と言われてきました.

でもおおきな文書のインスタンスをいただいて調べてわかるのですが、往々にしてこのパターンは存在するのです.「絶対にない」と言われたお客様でもありました.ここで、何が問題かといいますと、HTML出力ではたぶん問題になりません.何故かというとtopic単位にHTMLを作れば単にマップからのリンク先がたまたま同じtopicのHTMLファイルになるだけだからです.

でもPDFの場合は違います.PDFは内容をシーケンシャルに展開しなければなりません.例えば1章であるtopicを参照していて、第3章でも同じtopicを参照していたとします.同じ内容であっても第1章と第3章に「それ」が現われなければなりません.

これはidの管理からすると結構大変な問題になります.次のような例を作って試してみました.

<map id="map_AD7D77FBB75F416F80C1C50DC54DCD0B"> 
  <title>Id example</title> 
  <topicref format="dita" href="changing_the_oil.xml" navtitle="Changing the oil in your car" scope="local"/>
  <topicref format="dita" href="washing_the_car.xml" navtitle="Washing the car" scope="local"/>
  <topicref format="dita" href="oil.xml" navtitle="Oil" scope="local"/>
  <topicref format="dita" href="washing_the_car.xml" navtitle="Washing the car" scope="local"/>
</map> 

wasing_the_car.xmlは二回参照されています.これがDITA-OTのマージ後中間ファイルでどのような構造になるかと言いますと例えば次のようになります.2回参照されているwashing_the_car.xmlは実体はひとつです.

<dita-merge>
  <map>
    <topicref href="#unique1" type="task"/>
    <topicref href="#unique2" type="task"/>
    <topicref href="#unique3" type="concept"/>
    <topicref href="#unique2" type="task"/>
  </map>
  <task  id="unique1" oid="task_C20757FD77D34D7FA014B83C43532B23" xtrf="changing_the_oil.xml">~</task>
  <task  id="unique2" oid="task_91A0B128575846E8B769987E48E42EA3" xtrf="washing_the_car.xml">~</task>
  <concept id="unique3" oid="concept_CE6ED163BDE346398F9C348F35E2EDC3" xtrf="oil.xml">~</concept>
</dita-merge>

私の作ったスタイルシートでは、2つのwashing_the_car.xml参照から次のようなブロックを生成します.

<!-- 最初のwashing_the_car.xml参照-->
<fo:block id="task_91A0B128575846E8B769987E48E42EA3">
<!-- 二回目のwashing_the_car.xml参照-->
<fo:block id="task_91A0B128575846E8B769987E48E42EA3_2">

"_2"は二回目の参照を表します.こうればidが重複することはありません.また元のtaskのidを使っているので、PDFに書いたときに外部からこの部分を指定してジャンプすることも容易です.(CMSを使っているお客様では大本のtopic/@idは必ずユニークになるように管理されるのでこのようにしても大丈夫なのです.)

ちなみにDITA-OT搭載のPDFプラグインではどうなるか紹介しましょう.実はこのプラグインは手のつけられないほど中間ファイルを勝手に改造しています.出てくるのは次のような構造です.

<map>
  <opentopic:map>
    <topicref href="#unique1" id="unique_1" type="task"/>
    <topicref href="#unique2" id="unique_2" type="task"/>
    <topicref href="#unique3" id="unique_3" type="concept"/>
    <topicref href="#unique2" id="unique_2_ssol1" type="task"/>
  </opentopic:map>
  <task  id="unique1" oid="task_C20757FD77D34D7FA014B83C43532B23" xtrf="changing_the_oil.xml">~</task>
  <task  id="unique2" oid="task_91A0B128575846E8B769987E48E42EA3" xtrf="washing_the_car.xml">~</task>
  <concept id="unique3" oid="concept_CE6ED163BDE346398F9C348F35E2EDC3" xtrf="oil.xml">~</concept>
  <task  id="unique_2_ssol1" oid="task_91A0B128575846E8B769987E48E42EA3" xtrf="washing_the_car.xml">~</task>
</map>

なんと重複参照しているtaskはコピーされて実体部に現われます.そしてtopicref/@hrefは実は意味がなく、彼らが勝手に定義したtopicref/@idが実体を指していることになります.(ということはtopicrefに@idがあってもそれは消されてしまうのでしょう)

そしてこの二番目を表すid="unique_2_ssol1"の"ssol"は何かと言うと実はPDFプラグインをメンテナンスしている会社の頭文字です.いくらユニークなidを作ろうととは言え会社の頭文字を入れるというのはいまいちですね.このように生成したidは決してPDF外部から参照する術がありません.これは設計がだめな証拠です.

あと例えば、washing_the_car.xmlに手順の

<step id="step_C6FAA233B6F24112A609E1563CA35EC3">

があると、私の作ったスタイルシートでは

<fo:list-item id="task_91A0B128575846E8B769987E48E42EA3_step_C6FAA233B6F24112A609E1563CA35EC3">

を生成します.task/@idと組み合わせてユニークなidを作っているわけです.これがPDFプラグインでは、

<step id="unique_2_Connect_42_step_C6FAA233B6F24112A609E1563CA35EC3">

を生成します.

この"Connect_42"というのは何なのでしょう?これは[DITA-OT1.8]\plugins\org.dita.pdf2\xsl\common\topicmergeImpl.xslになんの解説もなく次のように登場する定数です.

<xsl:attribute name="href">
  <xsl:choose>
     <xsl:when test="$element-id = '' or not(starts-with(., '#unique'))">
        <xsl:value-of select="."/>
     </xsl:when>
     <xsl:when test="ancestor::*[contains(@class, ' topic/topic ')][1]/@id = $topic-id">
        <xsl:text>#</xsl:text>
        <xsl:value-of select="$newid"/>
        <xsl:text>/</xsl:text>
        <xsl:value-of select="$newid"/>
        <xsl:text>_Connect_42_</xsl:text>
        <xsl:value-of select="$element-id"/>
     </xsl:when>
     <xsl:otherwise>
        <xsl:value-of select="concat('#',$topic-id,'/',$topic-id,'_Connect_42_',$element-id)"/>
     </xsl:otherwise>
 </xsl:choose>
</xsl:attribute>

"Connect_42"にはどこにもなんの解説もありません.こういうのを見ていると、私はある意味「技術的退廃」を感ぜざるを得ません.

Yahoo!のdita-usersにはほぼ毎回のようにDITA-OT添付のPDFプラグインを自分向けに改造するための質問が寄せされていますが、こんな訳のわからない設計では見た人もまず理解できないだろうと思います.

id管理の結果は作成されたXSL-FOに現われます.お客様のなかでXSL-FOの中までのぞいてみた人はまずいないでしょう.コンサルタントやIAをやっている人も同様です.XSL-FOはPDFになるので、「まあPDFさえ出来てくれればいいじゃん」と考えるかもしれません.でもid管理ひとつ取ってもそこには技術レベルの到達点が歴然と現われているのだと思います.