Quantcast
Channel: tmakitaのブログ
Viewing all 102 articles
Browse latest View live

DITA 1.3詳解ワークショップ

$
0
0
3月16日(水)にDCJ(DITA Consortium Japan)の会員向けに、Eliot Kimberさんをお招きしてのDITA 1.3の詳解ワークショップが開催されました.わたしも同僚と一緒に参加する機会がありましたので感想を報告します.

まずDITAの歴史は非常に古くから検討され実践されてきたものということです.Eliot Kimberさんは元々IBM在籍されておられたそうですが、1980年代のIBM BookMaster、SGMLアプリケーションのIBM IDDocが元となっているとのこと、ID Docはモジュール化、リンキング、特殊化の考え方をすでに持っていたそうです.Eliot Kimberさんは、Don DayらとともにこのIBM IDDocの検討に参加され1992年にはそのバージョン1が完成、1998年のXMLの登場のもと、IBM DocのXML化が取り組まれ、これがDITAの源になったということです.(Kimberさん自身はその前にIBMを去っています)

日本でも2000年前半あたりはDocBook全盛だったので、DITAはDocBookより後発なのではないかという見方があるのですが、そうではなくXMLの登場以前に歴史をさかのぼることができるのですね.

そしてDITAは2003年にOASISに寄贈され、その後2005年にバージョン1.0、2007年にバージョン1,1、2010年にバージョン1.2、2015年にバージョン1.3と歩みを進めてきました.私も2005年のバージョン1は見た覚えがあります.まだindextermにsortasがなくて、「あ、これは日本語索引はつくれないな!」と思った記憶があります.

つぎに大きいのかDITA 1.2で取り入れられたキーの考え方です.それまでは、conrefもxrefも事実上の「ハードリンク」であり、topic間はいったんこれらを使ってみると分かちがたく結びつかれ、再利用が困難になります.しかしキーを使えば、conrefはconkeyreに、xrefもkeyrefを介した間接参照に置き換えることが可能です.これにより、再利用の可能性は大きく広まりました.(でもまだまだconrefは健在ですし、まだだと思いますが)

そして、DITA 1.3はこれらの上に立って、ブランチフィルタリング、スコープドキーの考え方が採用されました.スコープドキーを使用すれば、同じmapのなかでも異なったコンテンツを同じキーで参照可能になります.これは1つのpublicationの中で、複数のプロダクトの記述を行う場合に非常に便利です.ブランチフィルタリングを使用すれば、mapの中の異なる箇所で異なったDITAVALファイルによるフィルタリング条件を記述できます.これも同様にマルチプロダクトやマルチプラットフォームを記述するのpublicataionで有用です.

Kimberさんの話の中でも最も大きく時間を割いたのはこのキーの話だったと思います.キーを使えば、topicをハードリンクから解放して、ある意味「宙に浮かし」、どのようなコンテストからも使えるようになるからです.プレゼンの中でも、キーはDITAの間接参照の根幹を実現していると説明されました.

Kimberさんは「Always use key references」と何回も強調し、「ハイ先生!」と返事をするように言われていました.(「ハイ!先生」はKimberさんが入れ込んでいる、合気道の生徒が師匠にする返事だそうです.)

しかしいろいろ考えてみたのですが、実際のプロジェクトを考えてみると、なかなか「ハイ先生!」とは行っていない気がします.キーが使われないのです.それは多くのDITAの案件の発端が、「まずこのpublication(多くはマニュアル)のフローをDITA化したい」という「局所的」な出発点を持つものだからです.つまりDITAにするのでtopic化は了解するけれど、そのtopicがどのようなコンテキストからも使えるように、抽象化するということを真剣に考える作業はほとんどやられていないように思えます.何故かというと発端がDITAによる局所的最適化(たぶん)を目指しているからです.まあこれも止むを得ないかもしれません.SAPのように全社でDITAを取り入れているところのようにはゆかないからです.「まずこのマニュアルをDITA化して、次に展開する」というのはある意味、自然な成り行きなのでしょう.

しかし、局所的最適化の組み合わせは必ずしも大域的最適化にはなりえません.個々の最適化が、その範囲内にとどまっている限り、コンテンツの再利用範囲はその中に局所化されるからです.例えば.あるマニュアルを作るところから始まった場合、会社名、会社住所、ロゴのような大域的情報を、その後の展開に合わせてキーで設計できるでしょうか?IA(インフォメーションアーキテクト)の腕が試されます.

正直Eliot KimberさんのDITA 1.3の解説は大変すばらしく、いままでの生半可な知識も整理され、こういうのを応用したらどんなに素晴らしいか?と思うのですが、現実のプロジェクトを見るとまだまだという気がし、いささか暗澹たる気持ちになってしまいました.


DITA 1.3詳解ワークショップ(2)

$
0
0
DITA 1.3詳解ワークショップのEliot Kimberさんの解説を聞いていて感じたことを追加します.

DITA 1.3ではCross-deliverable linking、つまりbookmap間の参照(通常分冊間参照と呼んでいる)が出来るようになったという話です.これは具体的にはどのように行うのかというと、例えばmap01からtopicrefされているtopic1.ditaで次のようなxrefがあったとします.すると次のような別のmapを間接参照することにより、分冊間参照が「表現」できるというものです.

[topic01.dita]
<xref href-"topic-02">

[map01.ditamap]
<topicref href="topic-01.dita"/>
<keydef keys="topic-02" keyref="map-02.topic02"/>
<mapref keyscope="map-02" href="map02.ditamap" scope="peer"/>

[map02.ditamap]
<topicref keys="topic-02" href="topic02.dita"/>

[topic02.dita]
<topic>
 ...
</topic>

これは仕組みとしてscope="peer"で対象のmapが独立したルートマップであることを表すという意味付けを導入したことによります.ここで大切なのは「表現」であるということです.つまりDITAの仕様の中で、分冊間参照を仕様として表現できるようになったという点が重要なのです.表現と実装は異なります.この分冊間参照の仕組みは、現在のDITA-OTで実現されている訳ではありません.そして私はひょっとしたら、永久に実現はむつかしいのではないか?とも思っています.

例えばPDFの分冊間参照の場合、map02.ditamapとmap02.ditamapは別々にビルドされ、一定の(ユーザーの要望による)ファイル名が付けられるでしょう.実は分冊間参照は、最終的には「このPDFファイル名」+「ターゲットのid」という形にまで落とし込む必要があります.しかし、上記のオーサリングからは、PDFファイル名は知るすべはありません.またターゲットのidを知ることが出来たにせよ、topicにユニークなid付けを行いPDF生成ではそれを外部に参照先としてエキスポートするという処理なしには成し遂げられません.そもそもXSL-FOの仕様では、PDF内にこのidを埋め込むような仕組みはなく、各Formatter毎の独自仕様になっています.

またそもそもmap01.ditamapはPDFでpublishされるのかもしれませんが、map02.ditamapはHTMLでpublishされるのかもしれません.DITAは様々なメディアにpublish可能です.単にリンクが記述できるようになったと言ってもメディアが違えばリンクの生成方法も違うのです.

という訳で、分冊間参照はDITAの仕様の中で整合性を持って解決されたとはいえ、実装には程遠いのではないのかというのが私の感想です.しかしもちろん現実にはDITAで分冊間参照しているPDFは作られています.私もDITA 1.2を特殊化してxrefではないextxrefともいうべき要素を導入して、この仕組みを考案して実装しました.結局DITAの仕様はDITA-OTがそれをどのように消化するかにかかってきています.分冊間参照は技術文書では必須の機能ですが、やはり実装者が頭を悩ませて実現することに変わりはないのでしょう.

あとKimberさんに質問してお答えいただいたのですが、MathMLの実体参照の問題があります.DITA 1.3からMathMLのDITAインスタンスの中へのオーサリングが可能になり、<equation-block>とか<equation-inline>などMathMLを内包し、数式を表現する要素が導入されています.MathMLは実際にオーサリングする人がいて決しておかしくない機能です.同じDITAでもSVGとなるとさすがに手でオーリングする方は少ないのではないでしょうか?でも、MathMLは現実に使えるし、すでに大学ではDITA 1.3とともに使われています.

ここで問題になるのが実体参照です.数式は様々な数学記号を使用するので、文字参照では苦しいのです.名前付けされた実体参照の方がピンときます.例えばインテグラルだって、&Integral;と書けた方が&#x0222B;と書くよりわかりやすいでしょう.しかしOASISのDITA 1.3 DTDは実体定義のファイルをフォルダに含んでいるにもかかわらず、それを使用しない道を選択しました.つまりDITAでまともに書くとインテグラルは&#x0222B;と書くしかないのです、これはある意味苦痛でもあります.いちいちUnicodeのコード表を見ないとオーサリング出来ません.

これについてはKimberさんは次のような案を教えてくれました.

 ① 実体参照を使用しないことを選択する.
 ② 自分の特殊化したシェルDTDで実体定義をインクルードして使えるようにする.
 ③ DITAとは別のファイルのXMLを参照する.外部のXMLファイルならDITA 1.3 DTDの制限に依存せず実体定義+実体参照を使用することが可能です.
 
しかし、これらは決してOASIS DTDでは実体参照の使用を可能とすることを選択しなかった事実を変えるものではありません.会社のMathMLのサンプルを見たらみんなHTMLで実体参照を使って書かれていました.HTMLはそういう意味では楽です.サンプルを作るためにこれをXMLで書き直したことがありましたが、実体参照をすべて文字参照とするように、しなければならず非常に手間でした.

この問題はMathMLを使用する方にとっては結構大きい問題ではないかと思いました.

特殊化しない選択: data要素の使い方

$
0
0
DITAにはdata要素というたぶんフツーに使っていると「なんだこりゃ?」という要素があります.仕様は以下にあるのですが読んでも読んでもいまいちわかりません.

3.7.2 <data>

The <data> element represents a property within a DITA topic or map. While the <data> element can be used directly to capture properties, it is particularly useful as a basis for specialization. Default processing should treat the content as an unknown kind of metadata and ignore it for rendering, but custom processing might match the @name attribute or specialized element and use the element for automated manipulation or to format data associated with the body flow. For example, a specialized <data> element might be used to format properties as sidebars or other adornments or to harvest properties for automated processing.

今までこのdata要素をお客様が使っていた例はほとんお見たことがありません.唯一あったのが、data要素を単位量を表すのに使用していた例です.例えば、

<data datatype="kg">200.0</data>

として単位量を表します.この場合は200.0Kgを表します.でも上にあるように既定の処理は<data>要素は無視です.ですので一般的なスタイルシートでは

    <xsl:template match="*[contains(@class,' topic/data ')]">
    </xsl:template>
    
というテンプレートで読み飛ばしてしまうのです.ですので上記のような単位量は、可用性を考えるなら<data>要素は使うべきではないと思います.もし<ph>要素の特殊化だったら、最低限でも"200.0"というテキストは残ります.<data>要素を使ってしまったのではこれすら出なくなってしまうからです.

でもdita-usersを見ていたらKimberさんの投稿で、これが本当の意味での<data>要素の使い方なんだな~と思わせるものがありました.

Ordered lists - continue numbering?

やりたいことは、番号付きリストの開始番号をリスタートさせるか、それとも前の番号を引き継いでインクリメントしてゆくか?というものです.

<ol>
 <data name="enumeration">
   <data name="enumeration-stream-id" value="stream-01"/>
   <data name="enumeration-action" value="restart"/>
</data>
 <li>List item</li>
</ol>
...
<ol>
 <data name="enumeration">
   <data name="enumeration-stream-id" value="stream-01"/>
   <data name="enumeration-action" value="continue"/>
</data>
 <li>List item</li>
</ol>

上記は前の番号を引き継ぐオーサリングです.

DITA 1.3からは、<ol>の子要素に<data>要素も書けるようになりました.(1.2までは<li>のみです)なので、このようにDATA要素を使用して、

1. 番号付きリストの開始番号を制御する意味を表現する.
2. 他のDITAの処理系へ持って行っても、<data>要素は基本的に無視なので、害を及ぼすことはない.最低限の可用性は担保できる.

ということが実現できます.<data>要素はこのように使うのですね.しかしやはりこのような場合はolに属性をつけたくなるのが人情です.<data>要素は使い方を決めても、特殊化しない限り検証させて正確なオーサリングを保証するということはできないからです.

それがDITAの特殊化のルールに従っていなくともです.可用性を捨てるか?と言われればその通りなのですが.

ドイツ博物館で見た電子計算機の源流

$
0
0
たぶんITの業界で働いている方は、電子計算機の歴史を習うときに、昔は真空管で論理回路が作られ、それを山ほど集積して組み合わされて計算機システムが作り上げられたというような記述を読んだのではないでしょうか?私が業界に入ったころはそうでした.でも本や写真で読んだだけで実際に見たとか触ったとかしたことはまずありませんでした.

今たまたまドイツのミュンヘンに旅行で来ています.ホテルに一番近い観光スポットにドイツ博物館があります.ドイツのありとあらゆる産業技術の展示がこれでもかこれでもかとため息が出るくらい並んでいます.マニアックな人なら一日見ていても飽きないのでしょうけれども、私は女房と回りだして、寄る年波には勝てず、すっかり足腰が棒のように痛くなってしまいました.そんなときに出合ったのがコンピュータ関連の展示の場所でした.

ここで思わず体の痛みも吹っ飛ばすように目の前に飛び込んできたのが、超なつかしのカードパンチ機です.私は学生時代は応用数学でFORTRANをマークシートで紙カードにコーディングし、就職した1年目は官庁のSEルームに派遣で飛ばされプログラミングの仕事を始めたのですが、その頃の主役は紙カードだったのです.COBOLのソースコードはすべてカードで入力し、コンパイルエラーが無くなるまではカードを抜き差しして修正してたのです.ですので仕事場ではいつでもコンパイルリストと紙カードを持って歩く毎日でした.(もちろんTSS端末もあったのですが、すべてはお客様優先だったので、メーカーの派遣SEでは、おいそれとは触らせてもらえなかったのです.)

イメージ 1


ビックリしたのですが展示されているカードパンチ機というのはまったく見た目が自分がつかっていたのと変わらない作りなのです.当時何回もミスパンチをしたりして、やりなおしていました.今ではスクリーンエディタが当たり前ですが当時はそんなものだったのです.

次に目に飛び込んできたのは、本当に使われていたUNIVAC I(現Unisysの前身、Remington Land社製)でした.外から見ると「真空管の塊の要塞」です.メモを取っておいたのですが、1956年当時使用されていたもので、5,600個の真空管、18,000個のダイオード3,000個のリレーで構成されているそうです.いやはやすごい代物です.

イメージ 2


これが進化して真空管がトランジスタに置き換わっていった時代のシステムが、IBM 7070です.(ここには7074とありました)IBM7070は初めてのプログラム内蔵方式.これもびっくりしたのですが、中央処理装置、センターコンソール、カードリーダ、プリンタと私がある官庁に居た頃の、ホストマシンルームの構成と同じなのです.この最初の人形の前には、メモリのアドレス、データをコントロールするパネルが置かれています.これがプログラミングをやっている姿なのでしょうか?まさに機械語そのものを相手にしていたようです.

イメージ 3

イメージ 4


次はこの後継のシリーズの有名なIBM SYSTEM 360です.だんだんモダンになってきた感じがします.

イメージ 5


あと昔のパーソナルコンピュータの展示もありました.以下はIBM Personal Computer.IBMの昔のロゴが懐かしいです.まだキーボードは配列が英語101とは相当違います.

イメージ 6


それから日本勢も健闘していました.東芝のTシリーズ、あとちょっと見づらいですが、NECのMultispeed Laptopと言われる16bit, 9.54MHz, V30をCPUに搭載したラップトップがありました.V30なんていうCPUご存知でしょうか?8086の上位互換で、NEC PC9801-VMに搭載されていた覚えがあります.

イメージ 7


最後はIBMの1311磁気ディスク装置です.展示によると記憶容量は2.68MB.この機種ではないですが、私の就職した頃はリムーバブルディスクをメーカーから上からケースを装着してお客様のところまで宝物のように持ち歩いた記憶があります.今のスマホのSSDの容量と比べると涙ものですね.

イメージ 8


という訳でミュンヘンのドイツ博物館で、くしくも自分がIT業界に入ったころを思い出す、また本でしか習ったことのなかった黎明期のコンピュータの世界に出合うことが出来ました.特にIT業界はすさまじいスピードで進んでいるのですけれども、ちょっと昔を眺めなおしてみるのも大切でしょう.このような先人たちが切り開いてきた世界を垣間見せてくれたドイツ博物館に感謝したいと思います.

KZ-Gedenkstätte Dachau: ダッハウ強制収容所

$
0
0
ミュンヘン中央駅からS2という近郊電車に乗りおよそ20分もしないダッハウという町に、第2次世界大戦時ドイツで最初の強制収容所が立てられました.これがダッハウ強制収容所です.ここはユダヤ人、ナチスに反対したドイツ人、ポーランド人、ロシア人が強制労働の名の元に収容されましたが、1945年4月にアメリカ軍に解放されるまで3万人を超える人が亡くなったところです.

昔、早乙女勝元さんの「わが子と訪ねた死者の森収容所」という本を読み、いつか自分の子とこのような旅が出来たら良いものだと思っていました.しかし、日々の暮らしで精いっぱいで、とてもそんな機会が訪れるべくもありません.たまたま昨年いただいた高校の友人からの年賀状に長男とドイツの強制収容所を訪ねたという写真があり、今回ミュンヘンに来られたので一日取って女房と一緒に行ってみました.

ダッハウの駅前のバスから726番のバスに乗り、7つ目のまさにKZ-Gedenkstätteというバス停で降ります.バス停のすぐ左側に入口があります.中にはインフォメーションセンターがあって、平日にもかかわらず大変な人で混み合っていました.日本からも多くの人が訪れて様子をWEBに書いているのを目にしますが、この日行ったときは日本人は私たちだけだったようです.

ここが強制収容所の南に面した入り口です.皮肉にも「自由のために働け」と彫られた格子が残っています.

イメージ 1

イメージ 2

中に入ると広大な敷地の中に、様々な記念碑や建物があり、そして収容所棟が全部で20棟あったうち2つのみが復元されています.

イメージ 3

これが復元されていない収容棟の一つ18と書かれているのがわかります.奥はSS(ナチスの親衛隊)が見張りに使用していた監視塔です.この区画で定員250名.しかしアメリカ軍の解放時1600人が詰め込まれていて計3万人の囚人がいたということですから大変な状況だったのでしょう.

イメージ 4


私が敷地に入ってすぐ感じたのは、確実に過去に存在した多くの人の死を感じさせる何かあったということです.何故こんなに広いのかため息が出るほどでした.そして限りない静けさです.聞こえるのは小鳥の鳴き交う声、砂利を踏む人の足音、そして冷え冷えとした風のみでした.

以下は記念碑のモニュメントです.

イメージ 5


そして私がしみじみと考えさせられたのは、日本との違いです.日本で私が戦争という言葉で知らされてきたのは、被害者としての戦争体験がほとんどでした.広島・長崎への原爆投下、満蒙開拓団の悲劇、東京大空襲、沖縄戦.それはそれで大変意味深いことです.一方ドイツは加害者としての記憶、まさに自分たちにとっては大変な負の遺産であるに違いないのですが、これを決して隠さず、積極的に後世に教訓として伝えようとしている姿勢が感じ取れました.

それは何故でしょうか?この日多くの人が訪れていましたが、それは観光客というより、多くが学校(たぶん高校生)の見学グループだったからです.いくつもの集まりが順に敷地内を巡り歩いて先生の説明に真剣に聞き入っていました.こういうカリキュラムがあたりまえのこととして行われているのでしょう.また施設全体の印象からも積極性を感じ取ることができます.

国家的レベルでの認識の違い、今回のダッハウ訪問はそれを身をもって感ぜざるを得ませんでした.国家的レベル、それは侵略戦争すらも認めず、戦争責任もないがしろにしてきた日本の為政者の側の問題だけではありません.私たち日本人の一人一人の清算しきれない問題でもあると思います.ダッハウ強制収容所、ミュンヘンに行ったなら無理をしても行ってみる価値があると思いました.

属性の特殊化

$
0
0
九州地方地震で被災された方をお見舞いします.遅ればせながら災害募金をさせていただきました.

さて、掲題の属性の特殊化ですがずっと長い間理解が行き届いておらず、恥ずかしながらとんでもない遠回りをしていました.それは、GitHubで公開しているah-ditaの特殊化です.ah-ditaの特殊化は簡単に言えば、DITAのありとあらゆる要素でXSL-FOの属性(XSL-FOではプロパティと呼ぶ)を指定可能にし、可能なものにはそれをプラグインのスタイルシートで最終的に生成されるXSL-FOに反映させようとするものです.もともとXMLにこのようなスタイルを指定することは御法度なのですが、

① 表紙のように一定の自由度や微調整が要求される出力対象で、オーサリング側にスタイルを記述することにより、いちいちスタイルシートを直さないで済む.またユーザー自身で調整が可能.
② 出力結果のレイアウトを少しでも校正したい場合、オーサリング側にスタイルを記述できるので、急を要するときやどうしても直したい場合に簡単に対応できる.

という場合に利用できます.「御法度」ですが結構便利なのです.もちろん再利用という観点からはあまり勧められませんが.

ところでこのXSL-FOの属性を記述するのにah-ditaではfo:propという属性を使用しています.DTDでこれをDITAのおよそすべての要素に指定できるようにするための作業は意外と大変なのです.DITAには属性も種類と階層があり、一般的には"Universal attribute group"が多くの要素に使用され、そしてそれはID attribute group, Metadata attribute groupLocalization attribute groupDebug attribute groupから構成されています.しかし必ずしもすべての要素が"Universal attribute group"を適用できる訳ではなく、個別に追って指定を付け加えねばなりません.これがDTDでやると結構大変なのです.こんな要素にスタイルを指定することはないだろうとも思いながらも、しかしDTDを直すとなるときっちりとやらねばなりません.このような作業は非常に孤独でテストも大変です.あまりやりたくありません.

で気が付いたのですが、実はこのような作業はまったくやる必要がなかったということです.それはDITAでの属性の特殊化には2種類あり、@propsか@baseから特殊化します.@propsは条件処理のプロパティです.@baseは特に目的を規定していない属性です.有名なEliot Kimberさんの特殊化チュートリアルでは、次のように紹介されていて、早飲み込みしててっきり属性の特殊化は条件処理のみと思いこんでいました.


Chapter 5. Attribute Specialization Tutorial
Goal: Declare an attribute domain vocabulary module that provides a new conditional (property) attribute.

You can specialize from the @base and @props attributes. For conditional processing (filtering and flagging), this lets you add your own attributes rather than using @otherprops, which can be clearer to authors and implementors.

For this tutorial, the goal is to declare an attribute domain module that provides a new conditional attribute, in this case the "phase of the moon" condition, useful for medical information for werewolves and other lycanthropes.

ところが@baseはfo:propの用途には最適なのです.ともかく条件処理ではなく、全ての要素を対象に考えているのですから.そこでRELAX NGで作成すると概略次のようになります.

<grammar 
  <define name="xslfoAtt-d-attribute">
    <optional>
      <attribute name="prop" ns="http://www.w3.org/1999/XSL/Format">
        <a:documentation>Specifies the XSL-FO property to which an element applies.
        </a:documentation>
      </attribute>
    </optional>    
  </define>
  
  <define name="base-attribute-extensions" combine="interleave">
    <ref name="xslfoAtt-d-attribute"/>
  </define>
</grammar>

属性定義はこれでおしまいです.あとはtopicなどのシェルにこのモジュールを取り込むのみです.RELAX NGではcombine="interleave"とやりさえすればnameで指定した定義に自動的に加わってくれるのでまったく世話がありません.

1.domains属性に、"a(base fo:prop)"を加え、この特殊化が含まれていることを示します.("fo:"が少し心配です.)
2.topicなどのシェルに上記のモジュールを<include href="~.xml"/>でインクルードします.

すべてはこれでおしまいです.いちいちすべての要素を追いかけまわして属性を追加するような必要はまったくありません.OASISの提供しているスキーマを修正する必要もまったくありません.RELAX NGはネームスペースをサポートしますが、DTDはネームスペースを理解できません.このためDTDに落とした場合、いくばくかは手作業で修正が必要になるでしょうが、それでもごく限られた範囲でしょう.

せっかくなのでOASISのRELAX NGからXML Schema, DTDへのコンバーターを試してみましたが残念ながらXSLTでエラーでこけてしまいました.まだOASIS標準のものはOKでも特殊化を意図したスキーマは実績がないようです.

 oasis-open/dita-rng-converter

RELAX NGはDITA 1.3の公式のスキーマなので、早く特殊化したスキーマでも問題なくDTDやXML Schemaへ変換できるようになってくれれば良いと思います.

しかし属性の特殊化で@propでなく@baseを使用している例は見たことがありませんでした.こんなところが気が付かなかった落とし穴です.

CentOS

$
0
0
もう何年も前にお客様のシステムがRedHatのLinuxサーバーで動いていたので、そのメンテナンス用に会社でもライセンスをもらってサーバーを立てたことがあります.当時のディストリビューションはCDがいくつもの箱に入っていたのですが、当時は聞ける人も誰もおらず、何の知識もなしに必死でインストールしたことがありました.その後すべての開発とサポートはそのサーバーで行っていたのですが、クライアント版用にWindowsでも動くGUIを作ったので以降そのサーバーは机の隣でほぼ休眠状態になってしまいました.という訳で自分でサーバーを立てるというのはすっかり縁がなくなってしまいました.

しかしどうも世の中サーバー側の知識がないとやってゆけません.でも会社ではサーバーは厳格に管理されていて、自分でちょっと設定を触ってみるということはできません.この手のことは、なかなか実際にやってみないと理解も深まらないのも現実です.そこでそれなら自宅に立ててみようと思い立ち、あれこれ本を漁ってCentOSに決めました.マシンはというと、部屋の隅にほったらかしにしてあったWindows XPのデスクトップを筐体だけ活かしてマザーとCPUとHDDを交換して生き返らせ、いざやってみたら1日もかからず立ち上げまでたどり着きました.以下はFireFoxを立ち上げたところ.キーボードもPS/2で、もうウン十年前のIBM 5576-C01を使っているところが粋じゃないでしょうか?(実はC01は3台も持っています)

イメージ 1


でもここまで来る前には立ち上げるとBIOSでCPU Fan Errorが出てしまい、マニュアルで強制的にHDDを指定してブートしないと立ち上がりませんでした.おかしいなと思ってCPU(Core i5)を見るのですがファンは景気良く回っています.もう一度マザーのファンの電源の指口を見たら、あにはからんやCPU FANではなく、CHA FANに刺してしまっていました.これでファンの電源の指口を替えたらなんの問題もなくCentOSがブートされるようになりました.ヤレヤレ.あとマザーはASUSのH97 PROというのを使ったのですが、昔はLinux用のNICのデバイスドライバでさんざん苦労したので心配したのですけれども、今回はなんの問題もなくオンボードのネットワークアダプタを認識してくれました.メデタシ、メデタシ!

さてこれから何をCentOSに載せるかが楽しみです.ともかく自分が立てたサーバーなら何をやっても(自己責任ではありますが)文句は言われないのですから.

[1] は一個ではありません...

$
0
0
こんなことを書くと「あったりまえじゃん!」と言われそうですが、それでもXSLT 1.0のスタイルシートを見ていると意外とそのまま動いてしまっている例があります.それはXPath式でのロケーションステップに対する述語(predicate)の"[1]"という記述です.

例えば入力のXMLが

<?xml version="1.0" encoding="UTF-8"?>
<doc>
    <chapter>
        <para no="1">para-1</para>
        <para no="2">para-2</para>
        <para no="3">para-3</para>
        <para no="4">para-4</para>
    </chapter>
    <chapter>
        <para no="5">para-5</para>
        <para no="6">para-6</para>
        <para no="7">para-7</para>
        <para no="8">para-8</para>
    </chapter>
</doc>

という単純なものであり、XSLT 1.0で"1番目のpara要素の中身を出力しよう"と次のように書いたとします.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:template match="/">
        <xsl:variable name="para1" select="//para[1]"/>
        <xsl:message>//para[1]=<xsl:value-of select="string($para1)"/></xsl:message>
    </xsl:template>
</xsl:stylesheet>

結果は、oXygenでやると、

//para[1]=para-1

となります.なんの問題もありません.でもここで、xsl:stylesheetのversion="2.0"に書き換えて実行すると、

XPTY0004: A sequence of more than one item is not allowed as the first argument of string() (<para/>, <para/>)

のエラーになってしまいます.何か変です.デバッグのために、

<xsl:message select="'//para[1]=',//para[1]"></xsl:message>

と書いてやると、

//para[1]=<para no="1">para-1</para><para no="5">para-5</para>

と出てきます.アレッ!?話が違うようです.//para[1]は<para no="1">para-1</para>だけでなく<para no="5">para-5</para>も選択しています.そうなのです.ここで知らなければならないことは次のようなことです.

1. 述語(predicate)に"[1]"と書くと、それはコンテキストポジション(context position)の意味になります."[1]"は実は"[position() = 1]"と等価です.ここでposition()は評価されている要素の順番を返します.つまり対象はpara要素ですから、position()は、そのpara要素の親に対して何番目の子かということです.すべてのpara要素のうちの1番目ということにはならないのです.

2. もし文書中のすべてのpara要素のドキュメントオーダーで1番目ということだったら、<xsl:message select="'(//para)[1]=',(//para)[1]"></xsl:message>と書かねばなりません.こうすれば、(//para)[1]=<para no="1">para-1</para>と表示されます.評価されるものは文書中のすべてのparaのシーケンスだからです.その中での1番目を選択することになります.

3. XSLT 1.0では、string関数のパラメータが複数ノードの場合、最初のノードが選択されてその文字列値が返されます.XSLT 2.0ではこのようにはならず、string関数のパラメータがノードの場合、その個数は一個でなければ上記のようにエラーとなります.これはXSLT 2.0プロセッサを使っていても、XSLTスタイルシートのversion="1.0"か"2.0"かで異なった動作となります.

という訳でたかだか"[1]"であっても結構いろいろ知らねばならないことはあったのでした.参考になれば幸いです.


「いいね」と「+1の▲」

$
0
0
プログラミングで分からないことがあったらどうするでしょうか?たぶんいろいろ検索を試みてみるのが常ですが、そんな時によくヒットするのがstackoverflowのQ&Aです.この頃は日本語版のstackoverflowも出来て結構にぎやかなようです.


今日サイトの統計情報を見てみたら、1日当たりのビジターが6,376という数字なのでβ版といえどもみんな頼りにしているのでしょう.でも日本語版ではどうにもならないのが私がやっている業務の、xml, xslt,xsl-fo,ditaなどのキーワードです.これらには質問も回答もほとんどまったく投稿されないのです.本家の、stackoverflowだと

xmlで13万人
xsltで2万4558人
xsl-foで1040人
ditaで135人

のフォロワーという具合です.ところが日本だと

xmlで29人
xslt, xsl-fo,ditaはまだタグ登録なし

という散々な状況です.仕方がないので本家のstackoverflowの方へ行ってしまいます.英語ですが止むを得ません.

ちなみにstackoverflowは日本のQ&Aサイトなんかよりより「階級制度」(?評価制度)が厳しくて、その人の信頼度によって出来ることと出来ないことがあります.変な質問をしたり、間違った回答を書いていると評価は上がりません.参加者には評価やバッチが付けられます.これでその「人となり」がわかってしまいます.

例えばXSLTプロセッサのSaxonの作者のMichael Kay博士はなんと74,153の評価をつけられています.ともかくすごいです.この評価はそう簡単にはあがりません.Facebookなんかの「いいね」とは訳が違います.ちゃんとした役に立つ質問をしたり、的確で問題を解決する回答を書いて「▲」をクリックしてもらわないとなりません.(その「▲」のクリックすらノーバッチだとできません)

今xsl-foのタグの質問が投稿されたらメールをもらうようにしているのですが、この前やっと回答に対して「▲」をクリックして「1」の評価をもらい「teacher」のバッチをいただくことができました.

Force line break after string length

いやとても勉強になりました.日本のstackoverflowも本家並みにこれらのキーワードでにぎやかになってくれるとうれしいです.

統一コンテンツ戦略

$
0
0
DITAの和書というには非常に少ないので、たぶんDITAを検討されたり実践されたりしている方はご覧になっている本に、「DITA101 執筆者と管理者のためのDITAの基礎」(2011年刊 DITAコンソーシアム訳)があります.私も非常に参考にさせていただいています.

イメージ 1


ディテールにこだわりますが、この中のp.55からの「DITAの計画」の「統一コンテンツ戦略の開発」に次のように書かれています.

「DITAは、単なる構造化ライティングでも単なる再利用でもありません.方法論を転換して、再利用に、オーサリングの分担や協力に、そして 文書 よりもコンテンツのライブラリーに重点を移すことになります.このことはどのように作業するかを定義するための統一コンテンツ戦略を必要とします.
統一コンテンツ戦略とは、カスタマーへの最適供給のための最終的な(definitive)ソースにコンテンツを統一する(集める)ための実行計画です.
統一コンテンツ戦略についての詳細は、我々の本をご覧ください(Managing Enterprise Content: A Unified Content Strategy).統一コンテンツ戦略がなければ、DITAは コンテンツ作成の単なる一つの方法であり 、コンテンツへの付加価値はありません.」

結構大切なことが書かれています.DITAには統一コンテンツ戦略が必要で、そうしなければDITAを導入してもそれは単なるコンテンツの作成方法を変えただけで、コンテンツそのものに付加価値はつかないということなのです.

DITAを導入される動機はいろいろなものがあります.

・DocBookで作っていたがシステムが古くなってしまったのではやりのDITAで置き換えたい.
・IndesignやFrameMakerで作っていたが複数メディアの展開のためDITAに置き換えたい.
・多言語展開のための翻訳経費を削減したい.

これらは個々には大切な事柄ですが、いままでこれらを越えるようなお話はあまり聞いたことがありませんでした.それがコンテンツに付加価値を与える統一コンテンツ戦略なのでしょう.

まず「統一」のつかない「コンテンツ戦略」は次のように定義されています.


Content Strategy Definition
Getting the right content to the right user at the right time through strategic planning of content creation, delivery, and governance.

いわく、「戦略的なコンテンツ作成、配布、管理のもとで適切なコンテンツを適切なユーザーに適切なタイミングで届けること.」

つまりこれは(私的に意訳して考えれば)トピックのライブラリを作り、そこから必要なトピックをマップで束ねて、ユーザーの必要とするメディア(HTML、PDF、EPUB、もしくはVideo)などで如何に効率的で有効なタイミングで提供できるかが、今後の企業や組織の競争力を決する重要なポイントになるということで、DITAはそのようなコンテンツ戦略を支えるためのバックボーン(もしくは土台)の役割を担うであろうということです.

和訳されていませんが、DITA 101で言及されている、"Managing Enterprise Content: A Unified Content Strategy"(Ann Rockley、 Charles Cooper著)は、2002年に初版、2012年に改訂版が出ておりAmazonから入手できます.(評価は五つ星★です!)

イメージ 2



第一部「The basis of a unified content strategy」(統一コンテンツ戦略の基礎)の第一章の最初にはこのように書かれています.

Content: The lifeblood of an organization.
Organizations create tremendous volumes of content to support their products, services, and business processes. Getting content out to the right customer at the right time and in the right format is critical to an organizations's success.

拙訳:
コンテンツ: 組織の生命力
組織は膨大な量のコンテンツを、製品、サービス、ビジネスプロセスのために生み出しています.コンテンツを適切な顧客(ユーザー)に適切なタイミングで、適切なフォーマットで届けることが出来るか否かは、組織の成功にとって決定的に重要です.

統一コンテンツ戦略はこのようなものを目指すものなのでしょう."Managing Enterprise Content: A Unified Content Strategy"は洋書なので英語が苦手私にはなかなか読み応えがありますが、少し頑張って読み進めてゆきたいと考えています.

DITAをお考えの方も是非御参考にしていただければ幸いです.

topicの@xml:lang

$
0
0
xml:langという属性はXSL-FOからすると結構重要な属性です.例えば、とかく漢字は日本語を書いていると日本語フォントが選択されて当然と考えられるかもしれませんが、中国、台湾でも漢字はあたりまえに使われますし、ほとんど使われなくなってきているとはいえ、韓国でも漢字は人の名前に使われます.つまりUnicodeのCJK Ideographic(CJK統合漢字)は、その文字コードだけでは日本語フォントを当てはめるのか?中国語フォントを当てはめるのかはあいまいなのです.しかしxml:lang="ja-JP"をそのブロック(fo:block)に指定してあげさえすれば、適切に日本語フォントが選択されるでしょう.もちろん漢字といっても、簡体字のようにあきらかに中国本土でしか使用されないものもありますし、例えば「畑」なんていう漢字は実は日本製で、中国へ渡ったというものもあって成り立ちは一様ではありませんが.

しかしDITAのPDFの世界ではxml:langはあまり重要視されていなかったように思えます.それは、標準のPDF2プラグインが、ルートマップのxml:langのみを見て基本的な言語を判定している処理になっており、また少し前からはなくなりましたが、Unicodeの文字コードからフォントを選択するという(とんでもない)処理をやっていたからです.(これは2000年代の初めのIdiom Technologiesという現在ではSDLに買収された会社がこのプラグインの原型を作ったのですが、その当時からこのような処理が行われていたからにほかなりません.)

また、DITA-OTの処理も確かDITA-OT 1.8Xくらいからだったと思うのですが、個々のトピックにxml:langが指定されていなければ、デフォルトでen-USがつけられてしまうという、これもとんでもない処理でxml:langが扱われていました.

日本語でDITAのインスタンスを作るとき、個々のトピックにxml:langを必ず書くでしょうか?CMSを使用して言語展開している場合は厳格にCMSがxml:langを管理しますので、翻訳の過程で自動的につけてくれるはずです.しかしCMSをつかわずに手作業でいくつものトピックをつくっている場合、まずxml:langは書かないと思います.たぶんルートマップのxml:langをつければOKじゃないか?と考えるでしょう.

実は多言語の混在するようなトピックを処理できるように、PDFのプラグインを開発していた際、ルートマップにxml:lang="ja-JP"と書いても、個々のトピックを処理して中間ファイルに出すと、とたんにxml:lang="en-US"に一律になってしまってビックリしました.このような場合、少なくともルートマップのxml:langを尊重するか、せめて何も初期値を設定してほしくなかったのですが、今度のDITA-OT 2.3でようやくこのお願いをかなえていただくことができました.

TopicMerge sets unexpected @xml:lang attribute to topic.

現在最新のDITA-OT 2.3で試してみると、topic/@xml:langがない場合、topic/@xml:langには何も付かない仕様になっているようです.しかしこの障害報告を私がGitHubに出したのは2013年の3月です.足掛け3年でようやく実現してもらったことになります.なかなかDITA-OTのような世界的に使われているツールに仕様変更のようなものをお願いして開発者に理解していただき、直してもらうのは容易ではありません.ましてや英語で書かねばならず、ネイティブでない私が説得力のある文章を書くのはとても無理です.

実のところ本業の仕事が忙しいのでissueに出していないのですが、DITA-OTで直してもらいたい点はまだまだあります.恥をかきながらでも良いので、なんとかリクエストを出すのは継続しようと思います.

再起動

$
0
0
出張で高速バスに乗っていてPCでメールを見ようと思いスマホのデザリングを起動したのですがどうもうまく動いてくれません.どのようになってしまうかというとWindows 10のワイヤレスネットワークに警告マークが付き、ブラウザでサイトを閲覧しようとしてもDNSエラーになってしまいます.もちろんメーラーはまったくダメです.何度デザリングをON/OFFしても、PC側のネットワークアダプタをリセットしても結果は変わってくれません.結局その日は全然接続できずに諦めました.

この手のことにはとんと無頓智のため翌日auのサポートに電話して対処方法を聞きました.幾度か担当部署を替わってリモートアクセスまでしてもらってスマホの状態を調べてもらい、結局セーフモードで再起動したらデザリングはうまくいってしまいました.診断は何かアプリが干渉しているのではないか?ということです.対処方法を教えていただくと、「端末を初期化してください」とのことでした.これは大変です.PCだったらWindowsの再インストールのようなものですよね.バックアップやらアプリの再インストールとかいろいろ考えると嫌になってしまいます.

しばらく初期化する勇気が湧かずに、とりあえずセーフモードを解除しなければアプリも使えないと、とりあえず再起動しました.ところがやってみると、今度はデザリングはなんの問題もなく動くようになってしまったのです.しかも以前よりアプリもやたらサクサク動くようになってしまいました.要するに再起動が必要だったのですね!

これで思い出したのですが、昔Windowsがまだ3.1だとか95だった頃とかは、何やら動作がおかしくなると再起動が当たり前の世界でした.今でも会社のデスクトップのWindows 8.1は仕事が終われば落とし、出勤時には立ち上げますから事実上毎日再起動です.でもかつて今の会社に入ったころサーバーはNetWare全盛時代でした.年末にサーバー(確かNetWare 3.1)を落とすときに見せてもらったのですが、表示された連続稼働日数がほぼ360日でびっくりした記憶があります.だってその頃のWindowsはNT 4.0で、先進的にNTを入れたユーザーでももう毎日サーバーを落とすのが当たり前の運用と聞いていたからです.NetWareって本当に強固なOSでした.その後Windows NTの後塵を拝することになってしまいましたが...

ところが今のスマホはなんの気にもせずに毎日毎日ずっと使いぱなしでした.動くものがあたりまえに思っていたからです.でもやはりAndroidもまだまだなんですね.もちろんNetWareがたった16MBのRAMで動いていた時代とは比べ物にならないほどOSに要求される機能は高度になっているでしょう.しかし、どのようにOSが進化しても再起動はつきもののようです.

subjectSchmeで@outputclassを検証する

$
0
0
もしあなたがDTDやスキーマを特殊化しなければきっと@outputclassを使用するでしょう、@outputclassはいわば何でもありの属性です.

3.12.9 Other common attributes

Names a role that the element is playing. The role must be consistent with the basic semantic and expectations for the element. In particular, the @outputclass attribute can be used for styling during output processing; HTML output will typically preserve @outputclass for CSS processing.

もしある要素に何らかの特別なスタイル付けをしたければ、@outputclassはもっとも手軽に使える属性です.コンテンツが自由なので、値としてなんでも指定できてしまいます.逆に欠点は検証されないことです....とずっと思っていました.でも次の議論の中でOASIS Techinical ComittieのKristen James Eberleinさんから「@outputclassはsubjectSchemで検証できます」と指摘されました.(ちょっとスレッドが長く、該当箇所は後半の方です.)

Using Dita to produce image heavy PDF documents

これはちょっとショックでした.何故かというとsubjectSchmeはplatformなどのフィルタリング属性の値を定義するために使われるものばかりだと思っていたからです.実際DITA仕様にあるsubjectSchmeの例もplatform属性にOSに名前をバインディングするものです.

3.6.1.1 <subjectScheme>

では本当に出来るのか実際にやってみました.サンプルはxrefです.必ずDITAで出てくるのがtopicへのxrefなのですが、その出力結果として「(参照先topicの)タイトル」+「ページ番号」(title-page)、「タイトル」(title)、「ページ番号」(page)の3つが良くある出力パターンです.DITAの標準ではこれらをどうするかについては言及されていません.インプリメントする側がなんとかしなければならないのです.

これに対応するsubjectSchemeは次のようなものになります.これをメインのマップでmaprefして取り込めば良いのです.

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="urn:oasis:names:tc:dita:spec:classification:rng:subjectScheme.rng" schematypens="http://relaxng.org/ns/structure/1.0"?> 
<subjectScheme>
    <subjectHead>
        <subjectHeadMeta>
            <navtitle> Constraint @outputclass for xref</navtitle>
        </subjectHeadMeta>
    </subjectHead>
    <subjectdef keys="outputclassXref">
        <subjectdef keys="title">
            <topicmeta>
                <navtitle>Output destination title only</navtitle>
            </topicmeta>
        </subjectdef>
        <subjectdef keys="title-page">
            <topicmeta>
                <navtitle>Output destination title &amp; page</navtitle>
            </topicmeta>
        </subjectdef>
        <subjectdef keys="page">
            <topicmeta>
                <navtitle>Output destination page only</navtitle>
            </topicmeta>
        </subjectdef>
    </subjectdef>
    <enumerationdef>
        <elementdef name="xref"/>
        <attributedef name="outputclass"/>
        <subjectdef keyref="outputclassXref"/>
    </enumerationdef>
</subjectScheme>

実際oXygenで@outputclassを入力しようとしたときの画像です.ちゃんとDTDやスキーマで定義したがごとく属性候補が出てきます.(詳細は拡大してご覧ください.)

イメージ 1

そして@outputclassに候補でない値を入力した場合はちゃんとエラーが出てくれます.

イメージ 2

しかしDTDやスキーマで検証している訳ではないので、DITA-OTで処理させると検証エラーにはなりません.そしてDITA-OTでもエラーは出ませんでした.(これをDITA-OTに望むのは無理なのでしょう.subjectSchemはあくまでもキーを定義しているのですが、そのキーはコンテンツ自身からは参照されていないのですから)

しかしとにもかくにも@outputclassはオーサリングツールではsubjectSchmeで検証できました.これはうれしい知らせです.でももう少し凝ったことをやると思わぬ結果がでてしまいました.これは次回に書きたいと思います.

※ 2016/07/11追加
しかしDTDやスキーマで検証している訳ではないので、DITA-OTで処理させると検証エラーにはなりません.

これは誤りで、やり方により警告エラーが出る旨の御指摘をいただきました.警告が出るようにするためには次のようにします.

① SubjectSchmeを参照するmaprefにtype="subjectScheme"を指定します.
② これでxref/@outputclassにsubjectSchmeで指定されている以外の値を指定します.
③ oXygenでエラーが表示されますが、そのままDITA-OTに処理させます.例えばoutputclass="page-only"と指定した場合、

[DOTJ049W] The attribute value outputclass="page-only" on element "xref" does not comply with the specified subject scheme. According to the subject scheme map, the following values are valid for the outputclass attribute: page,title,title-page

とDITA-OTで警告が表示されます.ですので使えそうです.御指摘の中で参照されていたGitHubのやり取りは次のとおりです.結構前から実装されていたのですね.

Incorrect processing of subject scheme maps #1482


subjectSchmeで@outputclassを検証する(2)

$
0
0
ではどのような場合に不具合が出るのでしょうか?例えば@outputclassは様々な用途に使用されます.でも悩みの種は@outputclassは検証されない点です.subjectSchemaにより検証されれば、スキーマ/DTDを直すことなしに目的の結果を得ることができます.これはいいかもしれません.

考えた例は次のようなものです.

fig/@outputclass="none/left/right"
figgroup/@outputclass="auto/left/right"

と制限したいとします.そうすると作るsubjectSchemaは次のようなものになります.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE subjectScheme PUBLIC "-//OASIS//DTD DITA Subject Scheme Map//EN" "subjectScheme.dtd"> 
<subjectScheme>
    <subjectHead>
        <subjectHeadMeta>
            <navtitle> Constraint @outputclass for fig </navtitle>
        </subjectHeadMeta>
    </subjectHead>
    <subjectdef keys="floatLeft">
        <subjectdef keys="left">
            <topicmeta>
                <navtitle>Floats left</navtitle>
            </topicmeta>
        </subjectdef>
    </subjectdef>
    <subjectdef keys="floatRight">
        <subjectdef keys="right">
            <topicmeta>
                <navtitle>Floats right</navtitle>
            </topicmeta>
        </subjectdef>
    </subjectdef>
    <subjectdef keys="outputclassFig">
        <subjectdef keys="none">
            <topicmeta>
                <navtitle>No float</navtitle>
            </topicmeta>
        </subjectdef>
        <subjectdef keyref="floatLeft"/>
        <subjectdef keyref="floatRight"/>
    </subjectdef>
    <subjectdef keys="outputclassFigGroup">
        <subjectdef keys="auto">
            <topicmeta>
                <navtitle>Auto (Same as previous)</navtitle>
            </topicmeta>
        </subjectdef>
        <subjectdef keyref="floatLeft"/>
        <subjectdef keyref="floatRight"/>
    </subjectdef>
    <enumerationdef>
        <elementdef name="fig"/>
        <attributedef name="outputclass"/>
        <subjectdef keyref="outputclassFig"/>
    </enumerationdef>
    <enumerationdef>
        <elementdef name="figgroup"/>
        <attributedef name="outputclass"/>
        <subjectdef keyref="outputclassFigGroup"/>
    </enumerationdef>
</subjectScheme>

何故"floatLeft"や"floatRight"のようなキー定義を作るのは仕方がないのです.あくまでもキー定義なので、

<subjectdef keys="outputclassFig">
<subjectdef keys="outputclassFigGroup">

に同じキーを定義すると動作がおかしくなってしまうのです.ところがoXygenで出される候補を見ると、次のようにfloatLeftもfloatRightも出てしまうのです.これは望まれた結果ではないのですが、よくよくsubjectSchmeを考えてみるとあくまでもkeys/keyrefの機構をつかっているので止むを得ないのかもしれません.あげくの果てにDITA-OT 2.3.1でpublishすると画面のようにエラーメッセージが出ます.こちらもいまいちです.

イメージ 1

これはoXygenのフォーラムに出しましたが、Raduは[dita-comment]に質問を出してくれました.

Validating @outputclass by subjectScheme

Gathering restricted values using a subject scheme map

という訳で、残念ながら当面@outputclassをsubjectSchemで検証するというのは決着が付くまで無理ではないかと思います.

XSLTからPDFのページ数を取得する.

$
0
0
5月頃からXSL-FO、そして7月からXSLTの質問がStackOverflowにポストされたらダイジェストのメールが来るようにしました.XSL-FOの方はまだまばらですが、XSLTの量はすさまじいものがあります.7月1日から30日で324通のポストがありました.とても全部なんて見ていられません.XSLTは健在ですね.(この間日本のStackOverflowではたった1通のみです)

ちなみに質問の中に「XSLTから外部のPDFのページ数を知りたい!」というものがありました.実はこれはもう5年ほど前にJavaで外部関数をつくって実現していました.何故このような要望が出るかというと、特に表紙を作る場合、背幅を知るのにどうしてもいるのです.図で示すとこんな具合です.表紙/裏表紙を例えばA4で作っていると、背幅の分だけ幅を取ったPDFが必要になります.

イメージ 1


この背幅の計算は、コンテンツのPDFのページ数×紙の厚さで求めることができます.そうすれば、自動的に表紙のPDFを作れてしまうという具合なのです.

ちなみに、回答を書いたのですが、これにはPDFBoxというApacheのライブラリを使います.

How to return the (total) pagecount of external PDF files via XSL

私が作ったのはもう古くてPDFBoxが1.7の頃のバージョンでした.今回PDFBoxのJavaDocを見て「それなりに」コードを直したのですがポストしたらすぐ「お前のコードは古くて冗長だ!」とコメントがつきました.必死にもう一度最新のPDFBoxのJavaDocを見直して、アドバイス通りにコードを直すことができました.イヤApacheのPDFBoxもどんどん変わっているのですね.

ちなににこのコードをSaxonで実行するときには、Saxonの.jarの他に、commons-logging-1.2.jar、pdfbox-2.0.2.jarをCLASSPATHに入れておきます.

それにしても、世界の舞台はやはり厳しいです.ちょっとタコなコードを書くとすぐ手厳しい批判が来ます.でもとても勉強になります.また、この方法はXSLTスタイルシートから直接Javaライブラリを呼び出してページ数を得られるので、他の方法より簡単です.参考にしていただければ幸いです.


subjectSchmeで@outputclassを検証する(3)

$
0
0
すみません.このsubjectSchemeの書き方は私があまりに難しく考えすぎていたようです.次のようにすると問題なくoXygenで動いてくれます.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE subjectScheme PUBLIC "-//OASIS//DTD DITA Subject Scheme Map//EN" "subjectScheme.dtd"> 
<subjectScheme>
    <subjectHead>
        <subjectHeadMeta>
            <navtitle> Constraint @outputclass for fig </navtitle>
        </subjectHeadMeta>
    </subjectHead>
    <subjectdef keys="left">
        <topicmeta>
            <navtitle>Floats left</navtitle>
        </topicmeta>
    </subjectdef>
    <subjectdef keys="right">
        <topicmeta>
            <navtitle>Floats right</navtitle>
        </topicmeta>
    </subjectdef>
    <subjectdef keys="outputclassFig">
        <subjectdef keys="none">
            <topicmeta>
                <navtitle>No float</navtitle>
            </topicmeta>
        </subjectdef>
        <subjectdef keyref="left"/>
        <subjectdef keyref="right"/>
    </subjectdef>
    <subjectdef keys="outputclassFigGroup">
        <subjectdef keys="auto">
            <topicmeta>
                <navtitle>Auto (Same as previous)</navtitle>
            </topicmeta>
        </subjectdef>
        <subjectdef keyref="left"/>
        <subjectdef keyref="right"/>
    </subjectdef>
    <enumerationdef>
        <elementdef name="fig"/>
        <attributedef name="outputclass"/>
        <subjectdef keyref="outputclassFig"/>
    </enumerationdef>
    <enumerationdef>
        <elementdef name="figgroup"/>
        <attributedef name="outputclass"/>
        <subjectdef keyref="outputclassFigGroup"/>
    </enumerationdef>
</subjectScheme>

ちゃんとoXygenでも候補には期待したものが現れます.例えばfigだったら、none|left|rightです.

イメージ 1


問題はDITA-OTのようです.最新のDITA-OT 2.3.1でやると次のようなエラーが出てしまいます.@outputclassのleftとrightを有効な値として認識してくれないようです.

Description: [DOTJ049W] The attribute value outputclass="right" on element "fig" does not comply with the specified subject scheme. According to the subject scheme map, the following values are valid for the outputclass attribute: none
Description: [DOTJ049W] The attribute value outputclass="left" on element "fig" does not comply with the specified subject scheme. According to the subject scheme map, the following values are valid for the outputclass attribute: none
Description: [DOTJ049W] The attribute value outputclass="right" on element "figgroup" does not comply with the specified subject scheme. According to the subject scheme map, the following values are valid for the outputclass attribute: auto

oXygenはちゃんと理解してくれても、DITA-OTの方はダメということは、subjectSchemaによる@outputclassのバリデーションなんて世界で誰もやっていない(というかそもそも期待していない?)のかもしれません.よくわからないのでとりあえずDITA-OTのプロジェクトに障害報告を出して聞いてみたいと思います.

HTMLでXPathを使う.

$
0
0
ウェブスクレイピングという技術があるそうです.ウェブサイトから情報を抽出する技術のこと.TeraTailにVBAからMSXMLを使用してHTMLをパースし、XPathで必要な情報を取得したいという趣旨の投稿があありました.そもそもMSXMLでは入力がXHTMLでない限り(つまりHTMLをXMLとした扱えない限り)MSXMLだと無理ですと書いたのですが、まあ否定するだけではソリューションになりません.WEBを当たってみると.NETのDLLをCOM化する、つまりVBAからも扱えるようにするという話は結構掲載されています.ならばVB.NET + XPathでHTMLを検索できるのか試してみました.

ともかくVisual Studioを立ち上げるのは年に1回あるかないかです.恥ずかしながらすべてを忘れてしまっています.それでも昔作ったVBのプログラムを参考にしながら、WEBを調べるとHTML Agility Pack(https://www.nuget.org/packages/HtmlAgilityPack)というので、HTMLをパースできるところはわかりました.これを使って気象庁が出しているその日の気象情報から、地点と最高気温を抜き出してXMLに落とすプログラムを構想してみました.


簡単には、該当のテーブルを選んで、見出し行を除いてtrを取得し、0番目と6番目のセルの値を取得するだけです.
ところが結果は全然うまくいってくれません.HTMLを読めることは読めているようなのですが、まともにDOMに落ちていないらしく、XMLに書き込むと文字は化けるは、最高気温もデタラメと散々でした.

そこで別の方法はないものかと探したのですが、.NETのライブラリに同様にSGMLをXMLに落としてくれるオープンソースがありました.

SgmlReader - Convert (almost) any HTML to valid XML

こちらを使ってみると、なんの苦も無くほぼ一発でXMLに落とせました.そうです、HTMLというのはそもそも由緒正しきSGMLアプリケーションなので、SGMLのリーダーがあれば読めるのです.プログラムはこんな具合です.

[SgmlReaderを使ったプログラム]
Imports System.Xml
Imports System.Xml.XPath
Imports System.Text.Encoding
Imports Sgml
Module HtmlXPathModule
    Sub Main()
        Dim xw As XmlWriter = CreateXmlWriter("maxTemp.xml")
        xw.WriteStartElement("tempDataRoot", "")
        Dim sgml As SgmlReader = New SgmlReader()
        sgml.DocType = "HTML"
        sgml.IgnoreDtd = True
        Dim htmlDoc As XDocument = XDocument.Load(sgml)
        Dim nsTable As NameTable = New NameTable
        Dim nsMgr As XmlNamespaceManager = New XmlNamespaceManager(nsTable)
        nsMgr.AddNamespace("xhtml", "http://www.w3.org/1999/xhtml")
        Dim targetTrs As IEnumerable(Of XElement) = htmlDoc.XPathSelectElements("//xhtml:table[@class = 'o1']//xhtml:tr[@class != 'o1h']", nsMgr)
        For Each tr As XElement In targetTrs
            Dim targetTds As IEnumerable(Of XElement) = tr.Elements
            Dim tdArray As XElement() = targetTds.ToArray
            Dim region As XElement = tdArray(0)
            Dim maxTemp As XElement = tdArray(6)
            xw.WriteStartElement("tempData")
            xw.WriteAttributeString("region", "", region.Value)
            xw.WriteAttributeString("maxTemp", "", maxTemp.Value)
            xw.WriteEndElement()
        Next
        xw.WriteEndElement()
        xw.Close()
    End Sub

    Function CreateXmlWriter(outputPath As String) As XmlWriter
        Dim settings As XmlWriterSettings = New XmlWriterSettings()
        settings.CloseOutput = True
        settings.ConformanceLevel = ConformanceLevel.Document
        settings.Encoding = UTF8
        settings.Indent = False
        settings.NewLineChars = vbCrLf
        settings.NewLineHandling = NewLineHandling.None
        settings.OmitXmlDeclaration = False
        settings.WriteEndDocumentOnClose = False
        Dim xw As XmlWriter = XmlWriter.Create(outputPath, settings)
        Return xw
    End Function

End Module

[生成されたmaxTemp.xml(抜粋:最高気温の右の"]"は元からついています)]
<?xml version="1.0" encoding="UTF-8"?>
<tempDataRoot>
   <tempData maxTemp="27.1]" region="札幌"/>
   <tempData maxTemp="26.9]" region="稚内"/>
   <tempData maxTemp="26.0]" region="北見枝幸"/>
   <tempData maxTemp="28.0]" region="旭川"/>
   ...
   <tempData maxTemp="37.1]" region="鹿児島"/>
   ...
   <tempData maxTemp="33.0]" region="名護"/>
   <tempData maxTemp="32.7]" region="久米島"/>
   <tempData maxTemp="32.3]" region="南大東島"/>
   <tempData maxTemp="31.8]" region="宮古島"/>
   <tempData maxTemp="32.6]" region="与那国島"/>
   <tempData maxTemp="31.3]" region="西表島"/>
   <tempData maxTemp="33.1]" region="石垣島"/>
   <tempData maxTemp="" region="昭和"/>
</tempDataRoot>

この日は暑くて鹿児島は37℃を越えています.我が家も冷房がないので、このプログラムを作るのも汗だくです.

あともう一度トライしてみましたが、HTML Agility Packでも同じように動かすことができました.どうもエンコーディングがシビアらしいです.(このサイトでは)UTF-8を明示的に指定して、HTMLをいったんstringに落としてそこからパースすると動いてくれました.


[XML Agility Packを使ったプログラム]

Imports System.Xml
Imports System.Text.Encoding
Imports System.Net
Imports HtmlAgilityPack
Module HtmlAgilityTestModule
    Sub Main()
        Dim xw As XmlWriter = CreateXmlWriter("maxTemp.xml")
        xw.WriteStartElement("tempDataRoot", "")
        Dim wc As WebClient = New WebClient()
        wc.Encoding = UTF8
        Dim htmlSource As String = wc.DownloadString("http://www.data.jma.go.jp/obd/stats/data/mdrr/synopday/data1s.html")
        Dim doc As HtmlDocument = New HtmlDocument()
        doc.LoadHtml(htmlSource)
        Dim trs = doc.DocumentNode.SelectNodes("//table[@class = 'o1']//tr[@class != 'o1h']")
        For Each tr In trs
            Dim tds As IEnumerable(Of HtmlNode) = tr.Elements("td")
            Dim tdArray As HtmlNode() = tds.ToArray
            Dim regionTd As HtmlNode = tdArray(0)
            Dim maxTempTd As HtmlNode = tdArray(6)
            xw.WriteStartElement("tempData")
            xw.WriteAttributeString("region", regionTd.InnerText)
            xw.WriteAttributeString("maxTemp", maxTempTd.InnerText)
            Debug.WriteLine("region={0} max-temp={1}", regionTd.InnerText, maxTempTd.InnerText)
            xw.WriteEndElement()
        Next
        xw.WriteEndElement()
        xw.Close()
    End Sub

あと、同じことをXPathでなくLINQ とXMLでやったらどうか?ずっと疑問に思っていました.こちらも案ずるより産むが安しでStackOverflowに質問したらすぐ回答をいただけました.LINQもなかなか強力ですね.

このXPathはLINQ to XMLならどう書くのでしょうか?

という訳でお盆は暑かったのですが結構勉強になりました.普段XSLTやDITAやJavaばっかりなんですが、たまにはVisual Studioも動かすべきですね.

意外と大変なmap参照

$
0
0
同じPDFを作るのにも版下用に作成するのと閲覧用に作成するのは結構要件が異なります.特にいわゆる取扱説明書のように製品に冊子として添付する用途のPDFを作る場合、極力紙を節約するためにページ数をコントロールしたい要望があります.例えばchapterから成るbookmapの場合、次のように@outputclassでfo:page-sequenceをコントロールしたいという話がありました.

<bookmap>
  <mainbooktitle>PDF for printing</mainbookmap>
  <chapter navtitle="Chapter 1" href="chapter-1.ditamap" format="ditamap"/>
  <chapter navtitle="Chapter 2" href="chapter-2.ditamap" format="ditamap" outputclass="auto-even"/>
  <chapter navtitle="Chapter 3" href="chapter-3.ditamap" format="ditamap" outputclass="auto-odd"/>
  <chapter navtitle="Chapter 4" href="chapter-4.ditamap" format="ditamap" outputclass="auto"/>
  <chapter navtitle="Chapter 5" href="chapter-5.ditamap" format="ditamap" outputclass="auto-odd"/>
  <chapter navtitle="Chapter 6" href="chapter-6.ditamap" format="ditamap" outputclass="auto-even"/>
  …
</bookmap>

@outputclassの値は、各章のfo:page-sequence/@initial-page-numberに反映させたい意図です.こうすることにより各章の先頭ページを偶数ページから始めるのか、奇数ページから始めるのかをコントロールできます.

ところがこの方法には大きな落とし穴があります.それは、各chapterはサブマップを参照しているということです.例えばchapter-2.ditamapは次のようなものでしょう.

<map>
  <topicref href="chapter-2-1.dita" format="dita"/>
    <topicref href="chapter-2-2.dita" format="dita"/>
    <topicref href="chapter-2-3.dita" format="dita"/>
    ...
  </topicref>
</map>

一見何の問題もなさそうなのですが、実はchapter/@outputclassはマージ後中間ファイルに残りません.chapter-2-1.ditaを参照するtopicrefは、中間ファイルには例えば次のように展開されます.かろうじて@class属性には元がchapterであった痕跡を残してもらえる程度で@outputclassは出てきません.あくまで参照先のmap/topicrefの属性の有無が採用されます.

<topicref class="- map/topicref bookmap/chapter " 
          format="dita" 
          href="#unique_5" 
          type="topic" 
          xtrc="topicref:1;5:81" 
          xtrf="D:\SVN\samples\20160829-mappull\chapter-2.ditamap" 
          ohref="chapter-2-1.dita" 
          first_topic_id="#unique_5">
   ...
</topicref>

もしoutputclass="auto-even"を残したければサブマップの側に書いてやらなければなりません.

<map>
  <topicref href="chapter-2-1.dita" format="dita" outputclass="auto-even"/>
    <topicref href="chapter-2-2.dita" format="dita"/>
    <topicref href="chapter-2-3.dita" format="dita"/>
    ...
  </topicref>
</map>

でもこれだとサブマップの再利用性が落ちてしまいます.まあギンギンに紙を節約しようとするのですから、あまり他で再利用する意図はないのかもしれませんが.

ではchapter/@outputclassを得るためにはどのようにすれば良いのでしょうか?方法は3つほど考えられます.

① サブマップ参照の方法を変える.
これが一番簡単です.上記の例では

<chapter navtitle="Chapter 2" href="chapter-2-1.dita" format="ditamap" outputclass="auto-even">
  <mapref href="chapter-2.ditamap"/>
</chapter>

[chapter-2.ditamap]
<map>
  <topicref href="chapter-2-2.dita" format="dita"/>
  <topicref href="chapter-2-3.dita" format="dita"/>
  ...
</map>

とします.こうすればchapterレベルではマップ参照は発生しないので、@outputclassは残ってくれます.でもchapter全体をサブマップに定義したいという要望の場合、手間と感じるかもしれません.

② 自力でbookmapを読み込みchapter/@outputclassを取得する.

DITA-OTに任せるばかりでなく、自分でbookmapを読み込み、このファイルからマージ後中間ファイルのchapterに対応するchapter@outputclassを取得すれば可能です.でも自分で読むためには、スタイルシートも書かねばなりませんし、カタログファイルの設定も必要でちょっとテクニックが要ります.

③ DITA-OTを拡張する.

Eliot Kimberさんから教えてもらったのですが、DITA-OTにはこのようなマップ参照のスタイルシートをカスタマイズする機能があります.

Override styles with XSLT

dita.xsl.mappullという拡張機能(拡張ポイント)があり、これをプラグインで移用する旨宣言すれば、[DITA-OT]/xsl/preprocess/mappullImpl.xslを自分でカスタマイズできるのでしょう.しかしこれをやるにはDITA-OTの内部処理の深い知識が必要です.例えばマップ参照といっても様々なパターンがあり得ます.たまたまchapterから参照している場合は、サブマップの最初のtopicrefに@outputclassを反映させたいのですが、スタイルシートを見る限りそう簡単ではなさそうです.

という訳で簡単&お手軽の順では①>②>③となりそうです.なかなかマップ参照といっても簡単ではありませんね.

DITA-OTのカスタマイズ

$
0
0
DITA-OTには前処理の工程(preprocessと呼ばれる)があって、入力となるmapやtopicをパースし、conrefやフィルタリングなど様々な処理をやってくれます.ここでのDITA-OTの処理をカスタマイズできるのが「拡張ポイント」(Extension point)と呼ばれるものです.例えばDITA-OT 1.8.xの場合、つぎのような拡張ポイントが定義されています.

Override styles with XSLT

今まで拡張ポイントなんて使ったことがなかったのですが、前のポストで書いたようにどうしても修正が必要になってしまいました.なんとか自力でできたので、仕組みもそれなりにわかりました.すこしそれについて紹介します.

まず、topicrefからmapを参照するときに使用するXSLTスタイルシートは次の箇所で定義されています.

[DITA-OT1.8.5]/xsl/preprocess/mapref_template.xsl

これは実際に動くmapref.xslの雛型になるものです.次のような構造になっています.簡単ですので載せます.

<?xml version="1.0" encoding="UTF-8"?>
<!-- This file is part of the DITA Open Toolkit project hosted on 
    Sourceforge.net. See the accompanying license.txt file for 
    applicable licenses.-->
<!-- (c) Copyright IBM Corp. 2006 All Rights Reserved. -->

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:import href="maprefImpl.xsl"/>
    <dita:extension id="dita.xsl.mapref" behavior="org.dita.dost.platform.ImportXSLAction" xmlns:dita="http://dita-ot.sourceforge.net"/>
    <xsl:output method="xml" encoding="utf-8" indent="no" />
</xsl:stylesheet>

中ほどにある、dita:extensionというのがオマジナイです.DITA-OT 1.8.5をインストールした状態ではこれはmapref.xslで次のように変わっています.

<?xml version="1.0" encoding="utf-8"?><!-- This file is part of the DITA Open Toolkit project hosted on 
    Sourceforge.net. See the accompanying license.txt file for 
    applicable licenses.--><!-- (c) Copyright IBM Corp. 2006 All Rights Reserved. -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:import href="maprefImpl.xsl"></xsl:import>
   <xsl:import href="../../plugins/org.dita.specialization.eclipsemap/xsl/mapref-plugin.xsl"/>
   <xsl:output method="xml" encoding="utf-8" indent="no"></xsl:output>
</xsl:stylesheet>

このようにdita:extensionはxsl:importに変わっています.これはEclipse Helpのプラグイン(DITA-OT1.8.5/plugins/org.dita.specialization.eclipsemap)で、plugin.xmlが次のようになっているからです.

<feature extension="dita.xsl.mapref" file="xsl/mapref-plugin.xsl"/>

例えば私のプラグイン(com.myCompany.pdf)で同じように拡張ポイントを定義し、startcmd.batを実行して、ant -f integrator.xmlと叩いてプラグインを組み込めばmapref.xmlは次のように変わります.

<?xml version="1.0" encoding="utf-8"?>
<!-- This file is part of the DITA Open Toolkit project hosted on 
    Sourceforge.net. See the accompanying license.txt file for 
    applicable licenses.-->
<!-- (c) Copyright IBM Corp. 2006 All Rights Reserved. -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:import href="maprefImpl.xsl"/>

    <xsl:import href="../../plugins/com.myCompany.pdf/xsl/dita2fo_mapref_customize.xsl"/>
    <xsl:import href="../../plugins/org.dita.specialization.eclipsemap/xsl/mapref-plugin.xsl"/>
    <xsl:output method="xml" encoding="utf-8" indent="no"/>
</xsl:stylesheet>

きわめてよくできているように見えるかもしれません.しかしこのDITA-OTの拡張ポイントの定義には大きな問題があります.次にその問題について気が付いた点を書きたいと思います.

DITA-OTのカスタマイズ(2)

$
0
0
DITA-OTの拡張ポイントの定義には大きな問題があると書きましたが、それは次のようなものと考えています.

「DITA-OTの動作を自分(プラグイン)の「都合」で変えるのだから、他のプラグインに絶対迷惑をかけてはならない!」

これと同じような例がプラグインのbuild.xmlへの登録を担うintegrator.xmlにもあります.integrator.xmlは、DITA-OTのメインのビルドファイルに、自分(プラグインn)への制御の移行を組み込むものです.以前複数の会社で別々のプラグインを作り、お客様に納品する仕事をしていたことがありましたが、単独環境では動くのに、他社のプラグインを入れると参照している画像がすべて見つからなくなり、PDF出力のプラグインがエラー終了するという問題がありました.よくよく調べた結果、他社のHTMLのプラグインのintegrator.xmlが問題でした.自分の都合で、すべての画像ファイルをoutフォルダにコピーするプロパティ設定をしていたのです.HTMLでは必要でも、このような機能はPDFでは不要です.結局他社のプラグインのintegrator.xmlを直してもらったことがありました.

ましてやDITA-OTの動作を変える拡張ポイントの定義ですから他に迷惑をかけないよう、非常にうまくやる必要があります.ではそれはどのように行われているのでしょうか?参考に、あらかじめ組み込まれている、<xsl:import href="../../plugins/org.dita.specialization.eclipsemap/xsl/mapref-plugin.xsl"/> を見てみます.すると次のようなコーディングがあります.

  <xsl:param name="TRANSTYPE"/>

  <xsl:template match="/">
    <xsl:choose>
      <xsl:when test="contains($TRANSTYPE,'eclipse') and *[contains(@class,' eclipsemap/plugin ')]">
        <xsl:apply-templates mode="createPlugin"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

つまり、mapref.xslには$TRANSTYPE(DITA-OTで指定する-Dtranstypeの値)があって、これがパラメータで渡されるようであることがわかります.このeclipse.mapのプラグインでは、transtypeが自身であればmode="createPlugin"で自分に必要な処理をする、そうでなければ既定の処理をするという礼儀をわきまえたコーディングをやっていることがわかります.なるほどです.まあこれがDITA-OT 1.8.5 + XSLT 1.0でできる限りのコーディングなのでしょう.

このように書いたのは、拡張ポイントがxsl:importという機能を使用しているからです.このコードは../../plugins/org.dita.specialization.eclipsemap/xsl/mapref-plugin.xslにありますが、もしこれより後でxsl:importするプラグインが同じようなコードを書いたら、XSLTのimport precedenceの規則に従って後者の方が優先されてしまうのです.プラグインがどのような拡張ポイントを定義しているかは、別のプラグインからはわかりません.DITA-OTのintegrator.xmlがxsl:importの順番を決めてくれます.しかしこれとて規則性のあるものではないでしょう.

という訳で、DITA-OT 1.8.x + XSLT 1.0ではこれが限界です.もし処理がバッティングするなら、起動するDITA-OTを目的別に分けるしかありません.ちなみにDITA-OT 2.xでは、[DITA-OT]/xslのスタイルシートのXSLT 2.0に書き換えが行われています.ですので上記のプラグインはまだ救いがあります.次のように書けば良いのです.

  <xsl:template match="document-node()[contains($TRANSTYPE,'eclipse') and *[contains(@class,' eclipsemap/plugin ')]]">
     <xsl:apply-templates mode="createPlugin"/>
  </xsl:template>

こうすればまだいけるのではないでしょうか?XSLT 1.0では"["と""]"の中(述語:predicate)の中に、パラメータやグローバル変数への参照は書けませんでした.XSLT2.0ではかけるのです.では実際に最新のDITA-OT 2.3.2でどうなっているか見てみました.するとせっかくXSLT 2.0で書き直していたのにplugins/org.dita.specialization.eclipsemap/xsl/mapref-plugin.xslのコードは変わっていませんでした.これはバグとまでは言いきれませんが、十分コードの質を向上させる余地があります.

ちなみにいろいろえらそうなことを言っていますが、では私のコードはどうやったのでしょう?chapterやpartに特有な属性を参照したditamapの先頭のtopicrefに転記するというのは意外とあってもおかしくありません.以下にアーカイーブして置いておきます.よかったら御参考にしてください.(DITA-OT 1.8.5でしか動作確認はとってありません.もちろん他のプラグインに完璧に影響を及ぼさないようにはできませんし、他のプラグインのテンプレートで無効にされてしまう可能性もないとはいえません.)


Viewing all 102 articles
Browse latest View live