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

DITA 1.3の便利なフィルタリング属性deliveryTarget

$
0
0
DITA1.3はなかなか勉強する時間がありません.でも今度正式なスキーマになるRELAX NGで特殊化のサンプルを作ってみました.さてそれで実際に文書を作り、どんなことがDITA 1.3でできるのか考えていたとき、deliveryTargetというフィルタリングの属性が加わっているのに気が付きました.

3.12.1.2 Metadata attribute group

サンプルはここにあります.
2.2.3.8.4 Example: Defining values for @deliveryTarget

これはちょっと長いので、PDF出力でWEB用、カラー印刷用、モノクロ印刷用という簡単なSubjectSchemaを作ってみました.(私はあまりsubjectSchemeを作ったことがないのですが、これで合っていると思います)

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="urn:oasis:names:tc:dita:rng:subjectScheme.rng" schematypens="http://relaxng.org/ns/structure/1.0"?> 
<subjectScheme>
    <subjectdef keys="output-type" navtitle="Output Type">
        <subjectdef keys="pdf-web" navtitle="PDF For WEB"/>
        <subjectdef keys="pdf-print" navtitle="PDF For Print">
            <subjectdef keys="pdf-print-mono"  navtitle="PDF For Monochrome Printing"/>
            <subjectdef keys="pdf-print-color"  navtitle="PDF For Color Printing"/>
        </subjectdef>
    </subjectdef>
    <enumerationdef>
        <attributedef name="deliveryTarget"/>
        <subjectdef keyref="output-type"/>
    </enumerationdef>
</subjectScheme>

ではいったいどういう場面でこれを使うのかといいますと、特に画像の場合に有効に使えました.PDFの作り分けをするときにCMSを持っていらっしゃる方でしたら、元をEPSで作っておき、用途に応じてCMSが勝手にチェックアウトしてくれるような機能があります.でも手作りでやっているような場合、WEB用、カラー印刷用、モノクロ印刷用というような画像の切り替えは意外と面倒なものです.

例えば、画像を次のようにkeydefで定義しておけば便利です.この例ではWEB用にはSVG画像を、カラー印刷用にはカラーのPDFを、モノクロ印刷用にはモノクロのPDFを"COVER1-BACKGROUND"というキー値にマッピングしています.

[keydef_image.ditamap]

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="urn:oasis:names:tc:dita:rng:map.rng" schematypens="http://relaxng.org/ns/structure/1.0"?> 
<map>
 <title>Image Key Definition</title>
 <keydef keys="COVER1-BACKGROUND" navtitle="Cover 1 - background image" href="topics-en/image/cover_vector1.svg" format="svg" deliveryTarget="pdf-web"/>
 <keydef keys="COVER1-BACKGROUND" navtitle="Cover 1 - background image" href="topics-en/image/cover_vector1.pdf" format="pdf" deliveryTarget="pdf-print-color"/>
 <keydef keys="COVER1-BACKGROUND" navtitle="Cover 1 - background image" href="topics-en/image/cover_vector1_mono.pdf" format="pdf" deliveryTarget="pdf-print-mono"/>
 ...
</map>

DITAインスタンスからは単に次のように参照すれば済みます.

<image keyref="COVER1-BACKGROUND" placement="break"/>

あとは.ditavalファイルを作って、出力するPDF毎に切り替えます.このパラメータはDITA-OTを起動するときのコマンドラインで-Dargs.filterで指定します.

[print_color.ditaval]
<?xml version="1.0" encoding="UTF-8"?>
<val>
    <prop action="exclude" att="deliveryTarget" val="pdf-web" />
    <prop action="include" att="deliveryTarget" val="pdf-print" />
    <prop action="include" att="deliveryTarget" val="pdf-print-color" />
    <prop action="exclude" att="deliveryTarget" val="pdf-print-mono" />
</val>

[print_mono.ditaval]
<?xml version="1.0" encoding="UTF-8"?>
<val>
    <prop action="exclude" att="deliveryTarget" val="pdf-web" />
    <prop action="include" att="deliveryTarget" val="pdf-print" />
    <prop action="exclude" att="deliveryTarget" val="pdf-print-color" />
    <prop action="include" att="deliveryTarget" val="pdf-print-mono" />
</val>

[web.ditaval]
<?xml version="1.0" encoding="UTF-8"?>
<val>
    <prop action="include" att="deliveryTarget" val="pdf-web" />
    <prop action="exclude" att="deliveryTarget" val="pdf-print" />
    <prop action="exclude" att="deliveryTarget" val="pdf-print-color" />
    <prop action="exclude" att="deliveryTarget" val="pdf-print-mono" />
</val>

実際にやってみましたが、オーサリングをなんら変更することなく.ditavalファイルを切り替えるだけで、3種類のPDFが自動的に作られるのにはチョット感動しました.なかなかいいかもです.

XSLT2.0で便利になった機能(57) Xpathのコメント

$
0
0
XSLTというよりは、XPathの話なのですが、この前DITA-OTのxslフォルダのスタイルシートを見ていたら次のようなコードが出てきました.

<xsl:if test="(:not(@linking) and :)not($parent-linking='none')">

あまり見慣れていない"(:"と":)"という表記があります.これは何かというと実はXPathの中に書けるコメントです.

エッ!ホントなのか?と思われる方もいらっしゃるでしょうが、確かにXPathの仕様にちゃんと書いてあります.

2.6 Comments

何故このような表記になってしまったのでしょうか?CやC++では1行のコメントの"//"や"/*"と"*/"で囲むコメントが使われます.Pascalは"(*"と"*)"で囲むコメントが使われます.でもXPathでは、"//"も"*"もとても大事な意味を持っていますよね.なので混乱を防ぐために行き着いた先が"(:"と":)"だったのでしょう.

では、実際どのような時につかうのでしょうか?自分で身に染みて感じるのは次のような場合です.

- 最初は簡単だと思ってXPathを書く、けれどもうまく動いてくれない.
- あの条件もあった、この条件もあったとどんどんXpathが肥大化してゆく.
- で、何回も削ったり付け加えたりして、やっと目的のXpath式に行き着く.

この過程で、"削ったり付け加えたりして"というときに、コメントが使えると非常に便利なのです.トライアンドエラーでやっているとき、いちいち前のコードを全部消さないとダメなのは結構大変です."(:"と":)"で囲めば消さずに済むのでとても楽なのです.

でも最終的にあまり長いXPath式はxsl:functionに置き換えるのが良いと思います.その方がはるかに可読性は向上するからです.ここへたどり着くまでのデバッグの過程でXPath式のコメントは非常に役にたつでしょう.

以下の例は"element"という綴りがあるテキストノードを拾っていますが、//text()[contains(. (: commnet :), 'element')]と書いてちゃんと動きます.

イメージ 1

画像をオーバーフローさせずにページに収める.(1)

$
0
0
以前横幅の大きな画像を左インデントを考慮してページ右端までに収めるXSL-FOのコーディングを紹介したことがあります.それは、画像をfo:block-containerで囲んで、fo:external-graphicにcontent-width="scale-down-to-fit", width="100%"を指定するものでした.

fo:external-graphic

この時は次のようなFOを生成していました.

<fo:block-container border="2pt red solid">
    <fo:block text-align="center" start-indent="0mm">
        <fo:external-graphic src="url(hakumokuren.jpg)" 
                             content-width="scale-down-to-fit" 
                         width="100%"/>
    </fo:block>
</fo:block-container>

しかしこれではまずい現象が発生してしまいました.画像が十分小さい場合でも、テーブルに入れて横並びにさせると、テーブルの行は横幅いっぱいに広がってしまうからです.これはwidth="100%"を指定していることによります.width="100%"指定で、画像の幅にかかわらずテーブルのセルが目いっぱいに広がってしまうのです.このようにならないようにするにはwidth="100%"をmax-width="100%"に変更します.これで画像が大きい場合にのみ広がってくれます.

イメージ 1


<fo:block-container border="2pt red solid">
    <fo:block text-align="center" start-indent="0mm">
        <fo:external-graphic src="url(hakumokuren.jpg)" 
                             content-width="scale-down-to-fit" 
                         max-width="100%"/>
    </fo:block>
</fo:block-container>

例えばセルに幅指定をした場合もうまく収まってくれます.次の例の麦の写真とバイクの写真は両方ともページには到底収まらない大きなサイズですが、セル幅の指定に従ってその最大幅を限度に広まってくれます.

イメージ 2


話のオマケですが、ページの縦方向にも収まらない画像が出てきた場合はどのようにするのでしょう?これは一癖も二癖もありました.その(2)で紹介したいと思います.

画像をオーバーフローさせずにページに収める.(2)

$
0
0
画像がページの縦方向(ブロックの進行方向)にオーバーフローするのを防止するのにはどうしたら良いのでしょうか?実は横方向(インラインの進行方向)の場合、max-width="100%"としてやればすみました.これは次のようなものになります.つまり左インデントされた位置から目いっぱい取ってくれるのがmax-width="100%"なのです.

イメージ 1


でもこれと同じで縦方向の場合、max-height="100%"としたらどうなってしまうでしょうか?画像が配置されようとする位置から、ページ下部に向かって目いっぱい確保するのはmax-height="100%"になってしまいます.つまり、画像の配置される縦位置で画像の高さはどうにでも変わってしまうのです.

イメージ 2

これは非常にまずいです.私たちが欲しいのはたぶん以下の様なものです.

- 本文領域(fo:region-body)の高さに収まらなければ、その高さまで縮小する.
- そもそも画像の開始の縦位置から入らなければ改ページして本文領域の高さに収める.

本文領域の高さを表すのはビューポート領域の高さになります.それはFormatterの拡張である"vh"(Viewport Height)という表記で表されます.つまり結論から言いますと、次のようなFOで対応可能でした.

<fo:block-container>
  <fo:block start-indent="0mm" line-height="1" font-size="0mm">
     <fo:external-graphic src="url(flower_tate.jpg)"
                          scaling="uniform"
                          content-width="scale-down-to-fit"
                          max-width="100%"
                          content-height="scale-down-to-fit"
                          max-height="100vh"/>
  </fo:block>
</fo:block-container>

ここでfo:external-graphicを囲むfo:blockにline-height="1"、font-size="0mm"とある点に注意が必要です.これがないとまたオーバーフローしてしまうのです.理由は以下の様なものです.

- line-heightは上位から継承されます.フォントサイズが決まっていると、その上下にハーフレディング(half-leading)というアキ領域が取られます.これがオーバーフローの原因となります.line-height="1"とすることで、これを抑制します.
- font-size="0mm"は一般に画像がベースラインの上に乗る形で取られてしまい、フォントサイズのベースラインの下の分がオーバーフローするのを防ぐ目的でこの値を指定します.この仕組みは以下の図を見ていただければご理解いただけるでしょうか?

イメージ 3


という訳で、画像がページの縦方向(ブロックの進行方向)にオーバーフローするのを防止するのは結構ややこしい仕組みが必要でした.私もXSL-FOの勉強になりました.

fo:page-sequence ページ番号の制御

$
0
0
非常に素朴と言うか基本的な話なのですが、fo:page-sequenceのページ番号の制御で以前ハマっている例を見たことがあります.fo:page-sequenceというのは、XSL-FOのfo:rootの下の中核的なオブジェクトで一連の同じ特徴を持ったページコンテンツの集まりです.同じ特徴というのは例えば

1. 同じヘッダーやフッターの形式をしている(fo:static-contents)
2. 同じ規則のレイアウトのマスターを選択する(fo:page-sequence/@master-reference)

というようなものです.よく技術文書をpublishするときに印刷用、WEB用という使い分けをします.印刷用だったら、左右ページは左右のマージンを変え、目次や章は必ず右ページ(奇数ページ)に出して、最後のページは例えば4の倍数で終わらせるなどという条件がよくあります.でもWEB用だと印刷でなく閲覧用なので左右ページのレイアウトは同じで、目次や章も必ずしも奇数ページからはじまることをしない条件になります.もっともこのように印刷用とWEB用を作り分けると、お客様から「何ページの~は?」問い合わせがあった場合と言った時に、印刷した本とWEB用のPDFでページ番号が同じになっていないと困るので印刷用をそのままWEB用のPDFに流用する場合もあります.(でも見づらい場合もありますね)

さて、ページ番号でやはり一番問題となるのは印刷用です.fo:page-sequenceでページ番号を制御するのは次の2つのプロパティです.

・ initial-page-number
・ force-page-count

initial-page-numberは文字通りそのfo:page-sequenceをなんのページ番号で開始するかの指定です.force-page-countはそのfo:page-sequenceのページ数にどのような制約を加えるかという指定です.このような指定は一回やってうまく動いてしまうとそのままで、あとで直すことはめったにないのでとかく仕様を忘れがちです.基本は、どちらも"auto"が一番ということです.あとはこれに「必要な変更」のみ加えてゆきます.

例えば、章のfo:page-sequenceを必ず右ページ(奇数ページ)から始める場合は、initial-page-number="auto-odd"だけで済みます.ここで妙に「ならば前のfo:page-sequenceのforce-page-countをいじくってはいけません.例えば、force-page-count="end-on-even"などとする人がいます.でもそんな必要はまったくないのです.何故かと言うとforcae-page-count="auto"は

7.27.6 "force-page-count"

auto
Force the last page in this page-sequence to be an odd-page if the initial-page-number of the next page-sequence is even. Force it to be an even-page if the initial-page-number of the next page-sequence is odd. If there is no next page-sequence or if the value of its initial-page-number is "auto" do not force any page.

ということでautoにしておきさえすれば、次のfo:page-sequenceのinitial-page-numberプロパティを見て自動的にページ数を調整(必要だったら空白ページを入れるなど)を自動的にやってくれます.

ここで勘違いして「じゃあforce-page-count="no-force"でも同じか?」と考えてこの値を指定することは危険です.Formatterは"no-force"だとなんのページ制御の面倒も見てくれなくなります.この結果左右ページの順序(偶数:左、奇数:右)がなんの警告もなく崩れます.まずこの値は使う必要はありません.

あとforce-page-countを使用する箇所はpublishingの最後のfo:page-sequenceです.印刷用の場合、複数のページをまとめて印刷して裁断とかいろいろな条件があるので、XSL 1.1で定義されている、

auto | even | odd | end-on-even | end-on-odd | no-force | inherit

という値では到底足りません.これにはFormatterの持っている拡張属性を使用します.XSL Formatterでは、以下のように非常にフレキシブルな指定ができます.まず印刷用途のほとんどすべての要件に対応できるでしょう.

force-page-count

問題は、「最後のfo:page-sequenceを何をもって判定するか?」です.こればかりは入力データに依存します.例えばDITAだったら必ずchapterかappendixで終わる条件なら簡単に判別できるでしょう.でもbackmatterが入ってくると話はややこしくなります.backmatterは非常に自由度が高いからです.例えばbackmatter/booklists/indexlistの索引で必ず終わるというような条件をお客様からいただければ大変助かります.

ハマった例は、force-page-countだけでなく、左右ページ毎にレイアウトを変えているため、なかなかバグが入力データに依存して、見つかりづらいというものでした.例えば、章のfo:page-sequenceを奇数ページから始める場合、前のfo:page-sequenceのforce-page-count="auto"であっても、偶数ページの空白ページに対応したページマスターが必須です.またpublishingの最終ページを4の倍数で終わらせようとすれば、そのfo:page-sequenceが参照する(master-reference)ページマスターには、間違いなく左右の空白ページのページマスター定義が必要になります.

という訳でやはり印刷用というのは今も昔も難しいことに変わりはないと思います.要は必要なページマスターをちゃんと定義して、initial-page-numberとforce-page-countは"auto"から必要な箇所のみ変更を加えるということが基本だと思います.

DITA-OT Day 2015

$
0
0
昨年DITA Europe 2014カンファレンスへ行かせてもらった際に、その続きの日に開催されたDITA-OT Day 2014に参加してきました.いろいろな話が聞けて面白かったのですが、今年のDITA-OT Day 2015はDITA Eupopeカンファレンスの前日の11月15日に予定され、そのagendaが発表されています.

DITA-OT Day 2015

DITA-OT Dayはセッションとlightning-talkと呼ばれる短い発表から成りますが、今年はこの発表に応募させていただき、12:30 - 12:40のlightning-talkの時間をいただくことができました.題目はこのまえリリースしたPDF5-MLプラグインの話です.

AntennaHouse/pdf5-ml

たった10分という短い時間です.しかも英語音痴の私が話すので時間配分も含め大変行く末が案じられますが、今必死に原稿を推敲しているところです.まあ私の時代の英語教育では世界の場でこのようなプレゼンを行うなんてとても夢の様な話でした.ですのでこのような場を頂けるだけでも幸せです.
という訳で"Japanese English"ですが、なんとか世界の方にPDF5-MLの良さを知らせてゆけるよう頑張ってきたいと思います.

fo:page-sequence-master

$
0
0
この前fo:page-sequenceの話を出しましたのでついでに、そのページレイアウトを規定するfo:page-sequence-masterの話を書きたいと思います.と言っても仕様の解説という訳ではなく、陥りやすい間違いについてです.fo:page-sequenceはmaster-reference属性で参照するページマスターを記述します.印刷用に左右ページ、先頭ページ、左右を調整するための空白ページなどをおりまぜてパブリッシングするときには、fo:page-sequence-master/fo:repeatable-page-master-alternativesを使います.この子要素にはfo:conditional-page-master-referenceを使って、どのような条件の時にどのようなページレイアウトを適用するのかを記述します.例えば次のようなものです.

<fo:page-sequence-master master-name="pmsPageSeqChapter">
  <fo:repeatable-page-master-alternatives>
    <fo:conditional-page-master-reference master-reference="pmsChapterFirstLeft" 
                                          odd-or-even="even"  
                                          page-position="first"
                                          blank-or-not-blank="not-blank"/>
    <fo:conditional-page-master-reference master-reference="pmsChapterFirstRight" 
                                          odd-or-even="odd"  
                                          page-position="first"
                                          blank-or-not-blank="not-blank"/>
    <fo:conditional-page-master-reference master-reference="pmsChapterLeft" 
                                          odd-or-even="even"  
                                          page-position="any"
                                          blank-or-not-blank="not-blank"/>
    <fo:conditional-page-master-reference master-reference="pmsChapterRight" 
                                          odd-or-even="odd" 
                                          page-position="any"
                                          blank-or-not-blank="not-blank"/>
    <fo:conditional-page-master-reference master-reference="pmsChapterBlankLeft" 
                                          odd-or-even="even"  
                                          page-position="any"
                                          blank-or-not-blank="blank"/>
    <fo:conditional-page-master-reference master-reference="pmsChapterBlankRight" 
                                          odd-or-even="odd"  
                                          page-position="any"
                                          blank-or-not-blank="blank"/>
  </fo:repeatable-page-master-alternatives>
</fo:page-sequence-master>

この定義では、①先頭偶数ページ、②先頭奇数ページ、③(空でない)偶数ページ、④(空でない)奇数ページ、⑤空白の偶数ページ、⑥空白の奇数ページの順に参照するfo:simple-page-materを定義しています.そこで何が間違いやすいか?といいますとこの定義順です.①②は必ず③④の前に書く必要があります.③④と⑤⑥は条件が相反しているので、順番はどうでも良いです.

もし③④のあとに①②を書いたらどうなるでしょうか?この先頭ページのページマスターは決して組版の際には使われない運命となります.これはFormatterが組版の際にfo:page-sequence-master/fo:repeatable-page-master-alternativesを上から順にチェックして「最初に条件に一致」したfo:simple-page-materを使うからに他なりません.つまり条件の厳しいfo:conditional-page-master-referenceは、それより条件の緩いfo:conditional-page-master-referenceより前に書かねばならないのです.

この手のページマスターの定義は一回書いたら滅多に変更は起きません.なのでたまたま新規に作ったり、修正したりする時にこの書き順を間違えて期待した組版結果が得られず、「おかしいな~?」ということになることがあるのです.(少なくとも私は2回間違えました.プロの人なら間違えることはないでしょう.)

このことはXSL仕様では注として次のように記述されています.

6.4.11 fo:repeatable-page-master-alternatives

Because the conditions are tested in order from the beginning of the sequence of children, the last alternative in the sequence usually has a condition that is always true and this alternative references the page-master that is used for all pages that do not receive some specialized layout.

XML、XSLT

$
0
0
先月久しぶりに出張があった名古屋に行ったのですが、会議の始まるまでに時間があったので駅の周辺をぶらぶらしていました.たまたま三省堂があったので入ってみたのですが、やはりコンピューター関係のところに目が移ります.さすが三省堂で大きな棚がいくつもこの分野にリザーブされて本はあふれていました.そこでXMLの本はないかどうか探してみたのですが、HTML5やJavaScriptの本は山ほどあれど、なかなか見つかりません.やっと探し出したのが次の2冊です.

- XMLマスターベーシックの問題集
- 10日でおぼえるXML入門教室

いやはや如何にしてもたったこれだけなのか?という気がせざるを得ませんでした.XMLにしてこのありさまですから、XSLTについては絶無です.またXSL-FOは邦訳本が元々ありません.

私は決して(自分がHTMLやJavaScriptをやらない)のでいう訳ではありませんが、もっと基盤技術の本はあってしかるべきではないかと思います.

例えばDITAで人に伝えるコンテンツを作成するのに使用するのはXMLです.最近文書交換フォーマットをHTMLにすればすべてがうまくゆくみたいなことを言う人もいますが、決してHTMLは中核には成り得ないでしょう.変換の流れからすれば、大雑把に言えばDITA⇒[XSLT]⇒HTMLです.XSLTはDITAにスタイル付けをします.なので所詮HTMLは末端のフォーマットだと思います.これを伝えたい意味をオーサリングするXMLに取って変えようとする試みは、いくらHTMLからCSSでスタイルを分離しても、動機が誤っているとしか言いようがありません.

また最近StackOverflowの日本語版がお目見えしたのを御存じの方も多いと思います.StackOverflowの本家ではDITA, XSLT, XSL-FOの投稿が盛んですが、日本ではXSLはキーワードにすらなっていません.以下のQ&Aサイトでサーチしてみれば日本の「貧困さ」の度合いがわかるのではないかと思います.

スタックオーバーフロー

teratail

QA@IT

いったい、XSLTやXSL-FOに関わっている技術者はどこで疑問に対する回答を入手しているのか疑問に思えてしかたがありません.私が勉強を始めたころは日本で聞けるところはまずなくて、自分で何回も失敗してやってみるしか手がなかったのですが、まさか今でも同じなのかと思うとあまりにも残念です.

DITA-OT Day 2015 (報告)

$
0
0
去年のHoliday InnからHiltonに会場ホテルが変更になり、またDITA Europe 2015の前の日の開催となりました.事前の打ち合わせ議事録では約70人もの方が参加とのことです.このうちそれなりの割合の方がDITA Europe 2015には参加しないとのことでしたので、DITA-OT Dayも定着したのでしょう.

Meeting minutes 2015 11 04
Item 4: DITA-OT Day 2015

イメージ 1


さてAgendaは以前にも書きましたが、以下に出ています.私は12:30~12:40の10分でlightning talkとしてPDF5-MLのお話をさせていただきました.昨年はまだこじんまりとした会場で普通の机でやっていたのでそれを見て準備して行ったら、今年はなんと演台でやっています.演台はノートPCを置くので精いっぱいで、スマホのストップウォッチで時間を見ようとしましたがとても無理でした.

Welcome to the DITA-OT Day 2015!

プレゼンでお話したかったPDF5-MLのポイントを簡単に紹介させてもらいます.

最初は多言語対応です.PDF2やPDF5も含め今までのPDFプラグインはmap/@xml:langかbookmap/@xml:langからその言語に対応しているフォントをきめていておおよそ多言語対応とは言えませんでした.1つのpublicationで複数言語混在と言うのは鬼門だったのではないかと思います.PDF5-ML基本的にmapやtopicのあらゆる階層でのxml:lang指定を受付て、それに対応したフォントなどのスタイルを自動選択します.つまり真の意味で多言語に対応しています.

二つ目は条件付きの変数(variable)とスタイル(attribute-set)定義です.@output-type、@doc-type、@paper-sizeという属性をあらかじめ用意してあり、条件つきで変数やスタイルを定義できます.例えば、@output-typeだとWEB公開用("web")、カラー印刷用("print-color")、白黒印刷用("print-mono")などの値を持たせて、スタイルのカラースペース指定や、画像ファイルを記述できます.実際に何を選択するかはxsl:paramにマッピングされます.テンプレート側は@output-typeに対して「透過的」なコードにすることができます.つまり@output-typeを意識する必要がありません.

三つめは自由なフォーマットの表紙の作成機能です.これはah-ditaというDITAの特殊化DTD(DITA 1.2まで、DITA 1.3はRELAX NGのみ)を用いて、オーサリング側でXSL-FOのプロパティを@fo:propという属性にCSS形式で記述可能にし、これで自由なレイアウトの表紙を作れるようにするというものです.ただしbodydivからはfo:block-containerを生成することを前提としています.

3つにテーマを絞りましたが、10分ではまあ原稿を読み上げるので精一杯でした.また機会がありましたら詳しく紹介させていただければと思います.

私の話はともかく、DITA-OT Dayは面白い話がいっぱいでした.すべてはあとでPDFとビデオで公開されるそうですのでお待ちください.以下簡単に気の付いた点を紹介します.

DITA 1.3は2015年12月15日に出るそうです.Technical CommitteeのChairのKristen James Eberleinが言っていたのですから間違いないでしょう.

あと(私の記憶ではアナウンスはなかったと思いますが)DITA-OT 2.2が出ています.これは最初のセッションで紹介されていますが、相当変わっています.以下がリリースノートですが、DITA 1.3のスキーマが搭載され、PDF2の対応言語が増え、更にHTML5が加わっています.

DITA Open Toolkit 2.2 Release Notes

以上 簡単ですが御報告まで(ミュンヘンのHiltonホテルにて)

つながる世界、分断される世界

$
0
0
DITA-OT Day 2015/DITA Europe 2015に参加する機会を得て、名古屋から13日11時45分で出発し、ヘルシンキ経由でミュンヘンに到着したのは現地時間で13日の20:00でした時差が8時間ありますので、日本ではもう14日の朝方4時ということになります.

へとへとになってホテルにチェックインしたら女房のメールで「パリが大変なことになっている」という連絡です.部屋のテレビでBBCを選んだらBREAKING NEWSのテロップと共にパリのテロで120人以上が死亡のニュースが流れっぱなしでした.

イメージ 1

普段日本の片田舎で暮らしていると、ISのテロはまだ遠い国の話に聞こえますが、さすがミュンヘンに来て隣国フランスでこのような事件が起こっているとただ事ではありません.背筋にぞくっとするものを感じます.やはり世界は狭いです.

さてカンファレンスの間はホテルに缶詰め状態です.すべての日程が終わってから1日だけ有休をいただいて、ミュンヘンの市街を見てきました.と言っても「おのぼりさん」なのでSバーンに乗ってすぐのミュンヘン市の庁舎があるマリエン駅の周辺をぶらついただけです.ここで有名なのにレジデンス博物館があります.ここだけ見てきました.レジデンスはヴィッテルスバッハ王家の博物館です.とても日本では見られない荘厳さがあります.

イメージ 2

イメージ 3

ところがなんとここで日本の伊万里焼に出合ってビックリしました.事前の知識がなかったのですが、まさかミュンヘンに来て日本文化を目にするとは思わなかったからです.説明によると1600年から1700年にかけて日本から伝えられたとされています.

イメージ 4

イメージ 5


ドイツは中世の昔からアジアと「つながっていた」ということを改めて感じさせられました.世界とはそういうものなのでしょう.そうするとパリのテロリズムは一体何なのでしょうか?現代の「分断」と「断絶」の結果に他なりません.この二つの落差になぜこうなってしまったのか?と考えさせられます.

帰りにホテルにつく前に地下街にあるアジアンビストロという中華料理ファーストフードに立ち寄りました.数人のお客さんがいましたが、若いカップルが背を寄せ合って食事をしているのが正面に見えました.彼氏はどう見てもドイツ人です.彼女はあの特有のスカーフをまとったイスラム教徒の女性でした.彼氏が一生懸命彼女にやさしくしているのがわかりました.私には「分断」と「断絶」を越えるのはこのような人間の営みではないかと少し救われた気がしました.

DITA 1.3がOASIS標準に!

$
0
0
2015年12月18日のdita-commentsへの告知によれば、DITA 1.3はついにOASIS Standardとなりました.(でもWEBではあまり話題になっていないようです??秘密ではないと思いますが?)

---------- Forwarded message ----------
From: Paul Knight <paul.knight@oasis-open.org>
Date: Fri, Dec 18, 2015 at 1:18 PM
Subject: Darwin Information Typing Architecture (DITA) Version 1.3 becomes an OASIS Standard
To: tc-announce@lists.oasis-open.org, members@lists.oasis-open.org, voting@lists.oasis-open.org, DITA TC <dita@lists.oasis-open.org>

OASIS members:

OASIS is pleased to announce that Darwin Information Typing Architecture (DITA) Version 1.3 from the OASIS Darwin Information Typing Architecture (DITA) TC has been approved by the membership as an OASIS Standard [1].
...

12月3日の日本のDITAコンソーシアムに来日したIXIASOFTのKeith Schengili-Robertsさんの講演によれば、DITA 1.3の次はLightweight DITA(軽量化されたDITA)、そしてDITA 2.0というロードマップが展望されているとのことです.
いよいよ2016年はDITA 1.3が本格的に広まる年になりそうですね.

DITA-OT 2.2.1のチョンボ

$
0
0
DITA-OTは着々とDITA 1.3対応への準備を進めています.DITA-OT 2.2.xでは次のリリースノートに詳しく記述されています.

DITA Open Toolkit 2.2.1 Release Notes

このバージョンからDITA 1.3のスキーマが使用できます.DITA 1.3のスキーマは1.2と下位互換性があるため問題なく使用できます.

oXygenなどのXMLエディタを使用するとそれにバンドルされたDITA-OTを使用する機会が多く、独立してセットアップしたDITA-OTを使用する方はすくないかもしれません.その方が簡単だし、oXygenだったら最新のSaxonが使用できるからです.

でも私はほとんどの場合、バンドルされたOTは使用していません.実際にお客様のところで使用されるのは古いバージョンのSaxon 9.1であることが多く、とにもかくにも9.1で動いてくれないと困るからです.

ところで最新のDITA-OT 2.2.1はWindowsで動かすときに古いstartcmd.batを起動してant -f integrator.xmlと叩いてプラグインを組み込もうとしてもエラーになってしまいます.

イメージ 1


元々は、リリースノートにあるようにDITA-OT 2.2.0でバグ報告されてそれのメンテナンスリリースとして2.2.1が出ているのにまたバグってしまっているようです.メインの開発者のJarnoさんのメインマシンはMacのようなのでWindowsのstartcmd.batまでチェックが行き届かなかったのかもしれません.

ちなみにstartcmd.batはDITA-OT 2.xになってからは、もうditaコマンドに切り替えをというアナウンスがされています.

Lightning talk: Why "startcmd" is not your friend ()

たしかにそうなのでしょうけれども、1.8.5など以前のDITA-OTを使用しておられるお客様もおられるのでやはりstartcmd.batは必要です.ではバグフィックスされていないDITA-OT 2.2.1でどのようにしてプラグインを組み込めば良いのでしょうか?それはやはりditaコマンドを利用することです.以下のようにすればOKです.

1. plug-inフォルダに目的のプラグインをコピーする.
2. DITA-OT 2.2.1のフォルダの階層でコマンドウィンドウを開く.
3. bin\dita -install とコマンドを入力する.

イメージ 2


これでOKです.目的のプラグインはDITA-OT 2.2.1にちゃんと組み込まれます.

DITAは何故かくもむつかしいのか?

$
0
0
昨年だっと思いますがある日本の企業がDITAの導入を検討していて最終的に別のアーキテクチャを採用したというような話を聞いたことがあります.「DITAはむつかしすぎる」というのがその理由とのこと.それ以来ずっと頭の隅でくすぶっていたのですが、本当にDITAはむつかしいのか?ということです.
昨年11月にミュンヘンで開催されたDITA Europe 2015に行かさせてもらいましたが、2日目の最後にEliot Kimberさんの

  Why Is DITA So Hard?
  Understanding why people who are new to DITA are often overwhelmed when it's not really DITA's fault

  何故DITAはかくもむつかしいのか?
  DITAの初心者が本当の原因はDITAのではないのにいつも苦しむ訳

イメージ 1


と題したセッションがありました.出かける前から聞こうと思ってマークしておき、こちらのセッションに参加させていただきました.(でも意外と参加者は少なかったです.もう一つのセッションに行ってしまったのかもしれません.)

ではどのような内容だったのでしょう.

  DITAはオーサリングも、処理するのも.管理するのも難しい!
  それはDITAの責任か?
  答えはNO! それはDITAではなく「技術ドキュメント」そのものの責任である.

一瞬エッ!と思いました.続けますと

  DITAは複雑な技術文書固有の複雑さを表に出し、それを明白なものとする.
  DTPやDITA以外のシステムはこの複雑さを解決しない.
  
とされます.確かにWordで書いても技術文書はむつかしいのですが、Wordは単に叙述的に最初から最後まで書くしかなく、複雑なものはそのまま文書のなかに閉じ込められます.それをどうしようと考える術はありません.ただ書くだけです.

  DITA文書を根本的に構造化し管理する従来とはまったく別の方法である.
  DITAでなすべきことは複雑である.
  しかしそれは技術文書そのものが難しいことを反映している.
  DITAは多くの特徴を持っている.これらは他のXML言語やXMLアプリケーションでは決して成し遂げることはできない.
  
ではどうするか?KimberさんはここでDITAに「合気道」を適用しようと提唱します.ちょっとビックリ!(Kimberさんは相当合気道に入れ込んでいるようです)以下は合気道を紹介した箇所と、その適用について説明した箇所のスナップです.

イメージ 2

イメージ 3

実は、こんどの1月21日(早朝)にCOM Tech主催で、無料でKimberさんのWebnarが開かれます.題目から見て、このDITA Europe 2015の内容に近いか、それを発展させたものでしょう.

Why Is DITA So Hard? Understanding the link and configuration management challenges inherent in technical documentation.

夜中の2時でかつ英語というのはハードルが高いですが、是非ご覧になって損はないと思いますがいかがでしょう?私はこのような時は定時で帰って食事をしたらすぐ目覚ましをかけて寝てしまします.時間になったらもぞもぞと起きて毛布を羽織って聞くことにしています.(次の日の会社は眠いですが...)

XSLTスタイルシートから XSLTスタイルシートを作る!

$
0
0
一般的にXSLTスタイルシートはコツコツと手作りするものとずっと考えてきました.しかしある言語関係のテストをしなければならなくなり、さすがに一個一個手作りしていては間に合わなくなりました.というより、言語数が増えすぎて、とても手で作っていてはやっていられなくなったのです.

そこでXSLTスタイルシートを作り出すXSLTスタイルシートを考えてみました.ここで問題になるのは、xsl:のネームペースプリフィックスがついている(つまりネームスペースが、"http://www.w3.org/1999/XSL/Transform"である要素)はXSLTプロセッサが、自分が処理すべき要素として解釈するということです.これは当たり前なのですが、このスタイルシートを作り出すスタイルシートも同様にネームスペースが、"http://www.w3.org/1999/XSL/Transform"である要素の集合体であるということです.つまり、「自分で」「自分自身と似たもの」を作り出せなければなりません.

そこでXSLT 1.0から提供されているのが、

<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>

という宣言です.これは、XSLTスタイルシートの先頭で

<xsl:stylesheet version="2.0" 
    xmlns:axsl="file://namespace.alias"
    exclude-result-prefixes="xs xsl">
    
などとネームスペースプリフィックスaxslを暫定的に宣言しておき、xsl:namespace-aliasで指定したように、出力時にネームスペースプリフィックスを強制的に"axsl"から"xsl"に書き換えてくれます.これでバッチリXSLTスタイルシートを生成するXSLTスタイルシートを簡単に書くことができます.

例えばちょっと前後関係を省略していますが、次のような中国語簡体字用のXSLTスタイルシートから

        <xsl:result-document method="xml" version="1.0" indent="yes" encoding="UTF-8" href="{resolve-uri(concat('stylesheet/xslt',$pXsltVersion,'/dbtofo',$xsltVersionSuffix,'_',$xmlLang,'.xsl'),static-base-uri())}">
            <xsl:comment>DocBook to XSL-FO stylesheet for <xsl:value-of select="$xmlLang"/></xsl:comment>
            <axsl:stylesheet version="{$pXsltVersion}">
                <axsl:import href="{concat('common/dbtofo',$xsltVersionSuffix,'.xsl')}"/>
                <axsl:output method="xml" version="1.0" indent="no" encoding="UTF-8"/>
                <axsl:attribute-set name="atsRoot">
                    <axsl:attribute name="font-family">SimHei</axsl:attribute>
                </axsl:attribute-set>
                <axsl:variable name="cIndexTitle" select="'索引'"/>
                <axsl:variable name="cGroupTitleAlt" select="'记号,数字'"/>
            </axsl:stylesheet>
        </xsl:result-document>

次のようなXSLTスタイルシートを生成できます.

<?xml version="1.0" encoding="UTF-8"?>
<!--DocBook to XSL-FO stylesheet for zh-CN-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:import href="common/dbtofo2.xsl"/>
   <xsl:output method="xml" version="1.0" indent="no" encoding="UTF-8"/>
   <xsl:attribute-set name="atsRoot">
      <xsl:attribute name="font-family">SimHei</xsl:attribute>
   </xsl:attribute-set>
   <xsl:variable name="cIndexTitle" select="'索引'"/>
   <xsl:variable name="cGroupTitleAlt" select="'记号,数字'"/>
</xsl:stylesheet>

やってみるとわかりますが超便利です.今までは、言語毎にテストデータをXSLTスタイルシートで自動生成することはやっていましたが、今回それを処理するXSLTスタイルシートも自動で作れるようになりました.

ただしちょっと困ったのがantによる"繰り返し処理(ループ)"です.ループをするためには、例えば言語を表すプロパティを次々に変えてスタイルシートを作り出せねばなりません.でもご存知のようにantではプロパティはイミュータブルなのです.(書き換えることが出来ません)ですので元々のantには<for>に該当するものがないのです.これは次の機会に書きたいと思います.

あなおそろしきxsl:import

$
0
0
DITA 1.3のインプリメントをやってきてXML mention Domainの実装にさしかかりました.XML mention DomainはXMLの要素(<xmlelement>)や属性(<xmlatt>)を表す要素の集合体です.例えばxmlelementのp@class属性は次のようになっています.

class="+ topic/keyword markup-d/markupname xml-d/xmlelement "

これからいえることは、雑駁に言えばkeywordからmarkupnameが特殊化され、markupnameからemlelementが特殊化されたということです.ですので一般的なスタイルシートは

[dita2fo_bodyelements.xsl]
<xsl:template match="*[contains(@class, ' topic/keyword ')]">
[dita2fo_markup_domain.xsl]
<xsl:template match="*[contains(@class, ' markup-d/markupname ')]" priority="2">
[dita2fo_xml_mention_domain.xsl]
<xsl:template match="*[contains(@class, ' xml-d/xmlelement ')]" priority="4">

とpriorityで区別するものと考えていました.私のスタイルシートは実際そう作りました.ところがPDF2はどう作っているのか?と覗いてみると@priorityがないのです.

[commons.xsl]
<xsl:template match="*[contains(@class, ' topic/keyword ')]">
[markup-domain.xsl]
<xsl:template match="*[contains(@class, ' markup-d/markupname ')]">
[xml-domain.xsl]
<xsl:template match="*[contains(@class, ' xml-d/xmlelement ')]">

で実際に動かしてみると、テンプレートのバッティングは発生せずにエラーなしで次のような結果が得られます.xmlelementのオーサリングにはちゃんと前後に"<"と">"がついています.他もしかりです.

イメージ 1


何故こんなうまいことが出来るのだろうと調べてみたら、仕掛けはxsl:imortでした.

<xsl:import href="commons.xsl"/>
 ...
<xsl:import href="markup-domain.xsl"/>
 ...
<xsl:import href="xml-domain.xsl"/>
 ...

と順にインポートしているのです.このような場合、バッティングするテンプレートがあっても後からインポートした方がprecedenceが高くなり優先されるのです.そこでちょっとイジワルをしてxsl:importの順を変えてみました.

<xsl:import href="commons.xsl"/>
 ...
<xsl:import href="xml-domain.xsl"/>
 ...
<xsl:import href="markup-domain.xsl"/>
 ...

すると結果は次のようになります.すべてのxml-domainの要素はmarkupnameのテンプレートで処理されて、単にフォントがモノスペースになるだけです.
結果としてはまったくダメなのですが、オソロシイことに一切のエラーは報告されません.

イメージ 2


このxsl:importでtemplateの優先順位を制御するやり方はxsl:template/@priorityを管理しなくて済みます.そのかわりxsl:importの順序に細心の注意を払わねばなりません.順番を間違えてもエラーは出ないで、まったく期待しない結果になってしまうからです.

xsl:template/@priorityで制御する方法は手数がかかるかもしれませんが、@proorityの値を間違えるとXSLTプロセッサが「どちらのテンプレートにもマッチしてしまう!」というエラーを出すので、すぐ原因がわかります.また@rriorityの値により、その要素の特殊化のレベルもわかります.

xsl:importの順序で制御するやり方は分かっている人にとっては楽ちんなのかもしれませんが、私にはちょっとアブナイので従来通り@priorityで制御する構造のテンプレートにしたいと考えています.


antでループを実現する

$
0
0
XSLTではなくて本当はantの話なのですが、ついでに書きます.

与えられているミッションはプログラムのバージョン(3バージョン)×XSLTプロセッサ(約3種類)×50言語のテストデータというものです.これをテストしなければなりません.バージョン、XSLTプロセッサと1言語というビルドファイルは作ったのですが、これをバッチファイルで個々に起動させるというのはあまりに芸がありません.一発のantのビルドで少なくともプログラムのバージョン、XSLTプロセッサは固定でも50言語は繰り返しで処理してしまいたいというのが人情です.

でも、いくらantのUsers Manualを見ていても妙案は浮かびません.それもそのはず、繰り返し処理は必ずある変数(プロパティ)を順に変えながらそれをパラメータとして目的の処理を呼び出すという機構がどうしても必要だからです.antではここで変数はプロパティでしょう.しかしantのプロパティはimmutable(イミュータブル:不変⇒書き換え禁止)なのです.最初に設定した値が有効になります.例えばいくらビルドファイルの中で

    <property name="xml.lang" value="en"/>

としていても、antのコマンドラインで-Dxml.lang="ja-JP"とすればそちらが優先されます.つまり、プロパティの値を順に変えてという事自体が(純正のantでは)不可能なのでしょう.

しかし、繰り返しを一発のビルドでやってしまいたいというのは誰でも考えることです.Stack OverflowなんかのQ&Aを参考にして、antで<for>が書けるライブラリを見つけました.

  Ant-Contrib Tasks

ここでant-contrib-1.0b3.jarをant/libフォルダにコピーすればあっけなく使えるようになってしまいます.例えば次のような具合です.

    <!-- テストデータ作成用データファイルdita/testdata/sample_gen.xmlより
         test/@xml:langを抽出し、","区切りでプロパティlang.propsにセットする.
      -->
    <target name="iterate.lang" depends="build.saxon91.classpath">
        <property name="temp.dir" location="${basedir}${file.separator}temp"/>
        <mkdir dir="${temp.dir}"/>
        <local name="input.file.path"/>
        <property name="input.file.path" location="${basedir}${file.separator}..${file.separator}data${file.separator}testdata${file.separator}sample_gen.xml"/>
        <property name="output.property.path" location="${temp.dir}${file.separator}target_lang.xml"/>
        <local name="stylesheet.path"/>
        <property name="stylesheet.path" location="${basedir}${file.separator}stylesheet${file.separator}common${file.separator}make_lang_property.xsl"/>
        <java classname="net.sf.saxon.Transform" classpathref="saxon91.class.path"
            failonerror="true">
            <arg line='-o:"${output.property.path}"'/>
            <arg line='-s:"${input.file.path}"'/>
            <arg line='-xsl:"${stylesheet.path}"'/>
        </java>
        <xmlproperty file="${output.property.path}"/>
        <echo message="$${lang.props}=${lang.props}"/>
    </target>

    <!-- テストデータで定義された言語分のXSL-FO, PDFをビルドする.
     -->
    <target name="build.all.lang" depends="iterate.lang">
        <taskdef resource="net/sf/antcontrib/antlib.xml"/>
        <for list="${lang.props}" delimiter="," param="lang">
            <sequential>
                <local name="xml.lang"/>
                <property name="xml.lang" value="@{lang}"/>
                <echo message="$${xml.lang}=${xml.lang}"/>
                <property name="skip.pdf.generation" value="yes"/>
                <antcall target="build.xml.to.pdf.transform">
                    <param name="prm.xml.lang" value="${xml.lang}"/>
                </antcall>
            </sequential>
        </for>
    </target>

ここでlang.propsプロパティには"iterate.lang"で処理したい言語を","区切りで格納しています.例えば次のような具合です.

<echo message="$${lang.props}=${lang.props}"/>

${lang.props}=ar,bg,ca,cs,da,de,el,en,es,et,fa,fi,fr,he,hi,hr,hu,id,is,it,kk,km,kn,lo,lt,lv,ms,my,nl,no,pl,pt,ro,ru,si,sk,sl,sv,sw,ta,te,th,tl,tr,uk,vi

これをつくるXSLTスタイルシートも簡単なものです.単に言語タグを","で区切って並べるだけです.

[make_lang_property.xsl]
  <xsl:template match="tests">
    <lang.props>
      <xsl:apply-templates select="test"/>
    </lang.props>
  </xsl:template>
  
  <xsl:template match="test">
    <xsl:variable name="xmlLang" as="xs:string" select="string(@xml:lang)"/>
    <xsl:if test="position() gt 1">
      <xsl:text>,</xsl:text>
    </xsl:if>
    <xsl:value-of select="$xmlLang"/>
  </xsl:template>

元のテストデータは

<tests>
  <test xml:lang="ar"/>
  <test xml:lang="bg"/>
  ...
</tests>

という単純なものです.

しかし、こういうantの拡張は批判もあるようですね.Stack Overflowでは"ant-contrib-xx.jarはevilだ!"などという声もありました.しかし私にとっては背に腹は代えられません.この"Ant-Contrib Tasks"のおかげで、検証テストはぐっと簡単になりました.よろしくければ参考にしてください.

fo:block-containerとxsl:next-matchでランドスケープのテーブルを実現する.

$
0
0
DITA 1.3になって新たに加わった属性の一つとしてtable/@orient="land"があります.
  
  3.2.3.1 <table>

通常tableはブロックの進行方向に向けて行がだんだん配置されてゆくのですが、たまには列の項目が大きすぎて幅が収まってくれず、反時計方向に90°回転して配置したい場合が出てきます.このようなとき@orient="land"が指定できれば非常に便利です.

このような回転させたテーブルはどのように実現するのでしょうか?実はそれほど難しくはなく回転させたfo:block-containerでfo:tableを囲んでやれば良いのです.例えば次のような感じです.

<fo:block-container reference-orientation="90" break-before="page">
  <fo:table>
    <!--テーブルのコンテンツ-->
  </fo:table>
</fo:block-container>

問題はスタイルシートです.非常に素直に書くと以下のようになるでしょう.

<xsl:template match="*[contains(@class, ' topic/table ')][string(@orient) eq 'land']" priority="2">
  <xsl:choose>
    <xsl:when test="string(@orient) eq 'land'">
      <fo:block-container reference-orientation="90" break-before="page">
        <fo:table>
          <!--①テーブルの作成処理-->
        </fo:table>
      </fo:block-container>
    </xsl:when>
    <xsl:otherwise>
        <fo:table>
          <!--①テーブルの作成処理-->
        </fo:table>
    </xsl:otherwise>
</xsl:template>

ここで"①テーブルの作成処理"は中身は同じです.冗長なので別のテンプレートにくくりだしても良いかもしれません.しかし、このようなテンプレートの書き方は実は非常に「いまいち」なのです.XSLT 2.0のxsl:next-matchを使用すれば、今までのtableのコーディングを一切変えることなくたった数ステップのテンプレートを「追加」するだけで実現できます.それは次のようなコードです.

<xsl:template match="*[contains(@class, ' topic/table ')][string(@orient) eq 'land']" priority="2">
    <fo:block-container reference-orientation="90" break-before="page">
        <xsl:next-match/>
    </fo:block-container>
</xsl:template>

priority="2"とxsl:next-matchがミソですね.priority="2"で@orient="2"の指定されたtableはこのテンプレートの適用を優先させます.そしてfo:block-containerを作ったら、次にマッチングする(つまり通常のtableの)テンプレートを呼び出すのです.もちろんmatch="*[contains(@class, ' topic/table ')]"のテンプレートのpriorityは2より小さい必要があります.

しかし実にスマートです.一番良いのは「既存のコードに一切手を加えることなく実現できる」点です.これがXSLT 2.0の醍醐味とでもいうものでしょう.実装してみた例は以下の様なものです.(これは改ページさせていない例です)

イメージ 1


ちなみに、DITA 1.3ではセルの回転もあります.例えば列の見出しに条件を記述したくてかつ列数が多いような場合、これも90°回転させて表の見出し行を作りたい場合があります.特に機器のスペックなどを表す表の場合にたまたま見かけます.

3.2.3.7 <entry>

entry/@rotate="1"と指定するのですが、このスタイルシートの実装はそう簡単ではありません.同じようにfo:table-cellの中にfo:blcok-containerを入れて回転させてやれば良いのですが、こちらはセルの高さ(fo:block-container/@width)を明示的に指定してやる必要があります.この計算がXSLTでは困難なのです.という訳で同じtableのDITA 1.3での新機能ですが、こちらはまだ思案中です.

属性追加の欲望(1)

$
0
0
どうしてもOASIS標準の要素に自分たちで使用したい属性を付けたい場合があります.端的な例としてxrefがあるのではないでしょうか?例えばxrefがtopicを指す場合、

- topic/titleを""で囲んで表示(title-only)
- topic/titleを""で囲み次いでページ番号を表示(title-and-page)
- titleのページ番号のみ表示(page-only)

などと出し分けたい場合が確実にあります.しかしこのような属性はOASISの仕様では定義されていません.

3.2.2.40 <xref>

3.12.8 Link relationship attribute group

後者で@formatはリンク先のフォーマットです.@typeはリンク先が例えばtopicであるのか、fig,tableであるのかなどリンク先の種類を表します.つまり、xrefをどのように表示(出力)するのかというのはimplementation dependedとなります.ですので多くの場合取られる手段が汎用のoutputclassを使って識別するやり方です.例えば

<xref href="~.diata" format="dita" type="topic" outputclass="title-only"/>
<xref href="~.diata" format="dita" type="topic" outputclass="title-and-page"/>
<xref href="~.diata" format="dita" type="topic" outputclass="page-only"/>

という具合になります.これで十分機能するのですが、outputclassは汎用のスタイリング属性なので、パーサーによる検証で入力値を限定するということはできません.

3.12.9 Other common attributes

更に、すべてを@outputclassで吸収しようとしだすと、とても1属性だけでは足りなくなることがよくあります.ですので望まれるのは例えば次のようにxref/@outformatなどという属性を追加定義して記述できるとありがたいです.入力ミスも確実になくすことができます.

<xref href="~.diata" format="dita" type="topic" outformat="title-only"/>
<xref href="~.diata" format="dita" type="topic" outformat="title-and-page"/>
<xref href="~.diata" format="dita" type="topic" outformat="page-only"/>

このようなことはDITAの属性の特殊化でできるのでしょうか?残念ながらOASISの特殊化のガイドラインではこのようなことは推奨されていません.

2.5.3.5 Specialization rules for attributes

属性は@propsか@baseから特殊化しなくてはなりません.ここで@propsはフィルタリング属性です.@baseがフィルタリングのみに使用しなくても良いのですが、しかし

It is declared as a global attribute. Attribute specializations cannot be limited to specific element types.

ということで汎用の属性でなければならず、特定の要素タイプに使用を限定してはならないのです.大抵の場合、ここであきらめてしまうのではないでしょうか?つまり、このDITAの厳しい特殊化の制約に従っていては、現場のお客様の要求に答えることができないからです.なのでついついOASISの提供しているスキーマ/DTDを公開識別子を変えることはしても、次のように@outformatを追加してしまいたくなります.

[DTDの場合]
<!ENTITY % xref.attributes
             "href 
                        CDATA 
                                  #IMPLIED
              keyref 
                        CDATA 
                                  #IMPLIED
              type 
                        CDATA 
                                  #IMPLIED
              format 
                        CDATA 
                                  #IMPLIED
              scope 
                        (external | 
                         local | 
                         peer | 
                         -dita-use-conref-target) 
                                  #IMPLIED
              outformat 
                        (title-only | 
                         title-and-page | 
                         page-only | 
                         -dita-use-conref-target) 
                                  'title-only'
              %univ-atts;
              outputclass 
                        CDATA 
                                  #IMPLIED"
>

このOASISのガイドラインと現場でのインプリメンテーションの軋轢はやはりDITAの実践で直面せざるを得ない問題と思います.DITAは可搬性を重視しています.実際いじくりまわしたDocBookのインスタンスは決してそのシステムを離れて使うことはまず不可能です.しかしガイドラインに基づいて特殊化したDITAのインスタンスは、他のシステムでも最低限の処理を通すことができるからです.

今使っているDITAは本当に自分たちだけのものか?というと必ずしもそのような保証はありません.企業がグローバル化する中で、ある日突然の企業の合併吸収で、他人のDITAを自分のDITAと統合しなければならない場面も出てきかねません.

やはり標準に沿って自分たちのDITAを作るというのは必要なことでしょう.では既存の特定の要素に如何にして属性を追加するのか?最近のdita-usersの話を紹介したいと思います.

属性追加の欲望(2)

$
0
0
既存のOASIS標準の要素に属性を追加する例がdita-usersで議論されていました.

Rethinking "Custom" Attribute Specialization

ここで紹介されている方法は

1. @baseを特殊化して汎用の属性を追加する.例えば@foo
2. @fooを特定の要素、例えばtable要素に適用する制約条件モジュールを作る.
3. シェルのモジュール(DTD)でこの制約条件モジュールを加える.

こうすれば「厳格に特殊化のルールに適合する」ものではないにせよ、勝手に属性を追加するような「道を外れた特殊化」をしないで済むということになります.

「厳格に」というのは属性の特殊化条件は次のように述べられているからです.以下の条件は確かに満たされてはいません.

2.5.3.5 Specialization rules for attributes

It is declared as a global attribute. Attribute specializations cannot be limited to specific element types.

ここで紹介されている1~3の方法はDTDを用いたものです.DTDによる制約条件モジュールを作るのは、実体定義は「一番最初に行われたものが有効」という決まり事にすべてがかかっていると思います.ですので、制約条件モジュールは、

<!-- Constraint: Not including @foo in base attribute extensions: -->
<!ENTITY % base-attribute-extensions
""
>

と定義してtableに@foo属性を追加すれば済みます.base-attribute-extensionsは@baseの特殊化の実体定義です.これを""で打ち消してしまいます.こうして制約条件モジュールをシェルモジュールの先頭でインクルードすれば@fooは汎用の属性ではなくせるからです.

これをRELAX NGでやったらどうなるのか考えてみました.RELAX NGの場合、@baseの特殊化はたぶん次のような記述になるのではないかと思います.

  <define name="fooAtt-d-attribute">
    <optional>
      <attribute name="foo">
        <a:documentation>Specifies the foo property to which an element applies.
        </a:documentation>
      </attribute>
    </optional>    
  </define>
  
  <define name="base-attribute-extensions" combine="interleave">
    <ref name="fooAtt-d-attribute"/>
  </define>

特徴は、base-attribute-extensionsを定義するときに一般的にはcombine="interleave"を指定することです.この指定によりどこか別のbase-attribute-extensionsの定義とor条件になります.でもすごく便利なこの機能は、逆にいったん定義したものを打ち消すということはできないように思えます.ということは、そもそもbase-attribute-extensionsにfooAtt-d-attributeを最初から加えずに定義し、さも(?)汎用属性の扱いをしながらたとえばtable要素に属性として加えるということになります.

でも不安はつきません.DITA 1.3ではRELAX NGで大本のスキーマを記述し、それをDTDやXML Schemaに変換するという方法を取っています.上記のような方法では、はたしてまともに特殊化したRELAX NGをDTDに落とせるのでしょうか?

DITA 1.3はまだまだこれからなので、いまいちわからないことだらけです.

1★9★3★7

$
0
0
1937、イクミナ、征くみな

イメージ 1

最新の辺見庸さんの作品です.ただいま前半まで挑戦中.もう何年も前「もの食う人々」を読んだあとずっとご無沙汰でした.確かに問題作だと思います.帯封にもありますが、以下は序言のなかの何故この本を書いたかという一節です.

ではなんのために本書を著したのか.それはこうだ.わたしじしんを「1★9★3★7」という状況(ないしはそれと相似的な風景)に立たせ、おまえらならどのようにふるまった(ふるまうことができた)のか、おまえなら果たして殺さなかったのか、一九三七年の中国で「皇軍」兵士であるおまえは、軍刀をギラリとぬいて人を斬り殺してみたくなるいっしゅんの衝動を、われにかえって狂気として対象化し、自己を抑止できただろうか-と問いつめるためであった.おまえは上官の命令にひとりそむくことができたか、多数者が(まるで旅行中のレクリェーションのように、お気楽に)やっていた婦女子の強姦やあちらこちらでの略奪を、おい、おまえ、じぶんならぜったいににやらなかったと言いきれるか、そうしている同輩を集団のなかでやめさせることができたか-と責問するためであった.

大変「重い」本です.
Viewing all 102 articles
Browse latest View live