Hatena::ブログ(Diary)

名もないテクノ手 このページをアンテナに追加 RSSフィード

EPUB版『InDesign者のための正規表現入門』

InDesignのTips一覧

2009-03-23

[][][][][][][]IDMSことはじめ:(3)IDMSの検証

IDMS用スキーマの生成

IDMSの妥当性を検証をするためには、スキーマが必要です。書かなくちゃいけない? いいえ、InDesignが環境に合わせて書き出してくれるのです。書き出しにはJavaScriptを使います。

var my_folder = Folder.selectDialog ("IDMS用スキーマ書き出し:書き出しフォルダを選んでください");
app.generateIDMLSchema(my_folder, false);

選択したディレクトリに2つのファイルが作成されます。

f:id:seuzo:20090321180853p:image

  • datatype.rnc
  • IDMarkupLanguage.rnc

この「.rnc」拡張子で書き出されたファイルは「RELAX NG Compact Syntax」(RELAX NG短縮構文)と呼ばれる形式です。


Adobe純正ツールでの)IDMSの検証

IDMLやIDMSの検証には、Adobeの用意した/SKD/devtools/sdktools/idmltoolsディレクトリに含まれる「validate.sh」(Mac)が使用できます。パスの通し方などは「InDesign CS4 IDML ReadMe(抄訳) - 名もないテクノ手」などを参照してください。

前述のようなディレクトリがカレントディレクトリであるとき

$ validate.sh schima/ *.idms

とすれば、すべてのIDMSファイルを検証できます。スキーマはディレクトリで指定する必要があります。2ファイルをわざとエラーが出るように書き換えてあります。下記のようなエラーがでました。

/Users/show/Desktop/IDMS/myOval.idms:5:82: error: required attributes missing
/Users/show/Desktop/IDMS/my_XML2.idms:5:22: error: element "Spread3" not allowed in this context

myOval.idmsの5行目に必要な属性がないこと、my_XML2.idmsの5行目のSpread3エレメントは文法違反になります。


Rubyでの)IDMSの検証

Adobe純正ツールは確かにお手軽で便利なのですが、Javaツールなので実行コストが高いことや、(サーバー上で)Rubyから外部コマンドをキックすることのためらいがあります。やはりRuby内で生成したIDMSをRuby内で検証したいのが人情ってものでしょう^^

だがしかし! ここに2つの問題があります。

  1. Rubyの各種XMLライブラリはRELAX NG Compact Syntaxをサポートしない
  2. Rubyの標準ライブラリREXMLでは、スキーマの扱いにいくつかの不具合がある

ここでは、問題1を回避するためにTrangを使って、RELAX NG Compact Syntax形式をRELAX NGに変換します。スキーマが動的に必要でないなら、1度変換したスキーマを使い回せばいいのです。

問題2を回避するために、REXMLではなくて、LibxmlのRubyバインディングであるLibxml-Rubyを導入することにしました。


Trangを使ってスキーマの変換を行う

Trangはこちらからダウンロードできます。.zipアーカイブを伸長したら、ターミナルから下記のように実行します。

#実行にはJava環境が必要です。マニュアル参照。また、trang.jarにはパスが通っているものとします。

$ cd /foo/var/schima/  #スキーマがあるディレクトリに移動
$ java -jar trang.jar IDMarkupLanguage.rnc IDMarkupLanguage.rng

第1引数が入力ファイル、第2引数が出力ファイルになります。特にオプションを指定しない場合、フォーマット形式は拡張子を自動判定して決定されます。「IDMarkupLanguage.rnc」の7行目には「include "datatype.rnc"」が書かれているので、「datatype.rnc」も一緒に変換されます。実行すると、下記のように「IDMarkupLanguage.rng」「datatype.rng」が生成されました。

f:id:seuzo:20090323164007p:image


Libxml-Rubyを使ってIDMSの検証をする

gem環境があるなら、Libxml-Rubyのインストールは簡単です。

sudo gem install -r libxml-ruby

これで準備が(ようやく)整いました。さっそくIDMSの検証をしてみます。マニュアルにあるとおり、以下のスクリプトを実行します。

begin
  require 'rubygems'
rescue LoadError
end
require 'xml/libxml'

# parse schema as xml document
relaxng_document = XML::Document.file('schima/IDMarkupLanguage.rng')

# prepare schema for validation
relaxng_schema = XML::RelaxNG.document(relaxng_document)

# parse xml document to be validated
instance = XML::Document.file('my_XML.idms')


# validate
instance.validate_relaxng(relaxng_schema)

あれ? 実行エラーが出ます。

Warning: failed to load external entity "datatype.rng".
Error: xmlRelaxNG: could not load datatype.rng.
Error: Failed to load include datatype.rng.
・#あとは延々とエラー
・
・

「datatype.rng」がねえよ、と言っているわけですね^^。実行スクリプトから見て、「IDMarkupLanguage.rng」は「schima」ディレクトリに入っています。ですから、「IDMarkupLanguage.rng」に6行目に書かれている

  <include href="datatype.rng"/>

  <include href="schima/datatype.rng"/>

に書き換えておく必要がありました。あるいは、どちらのスキーマも実行スクリプトと同じ階層に置いておくとか。

IDMSが正しく検証できれば、このスクリプトは無言です。楽しくないので、わざとタグ名を変更したファイル「my_XML2.idms」を指定してみました。すると...

Error: Expecting element Language, got Spread3.
Error: Expecting element FontFamily, got Spread3.
Error: Expecting element TextVariable, got Spread3.
Error: Element Document has extra content: Spread3.
test.rb:21:in `validate_relaxng': Error: Element Document has extra content: Spread3. (LibXML::XML::Error)
	from test.rb:21

と正しく指摘してくれます。めでたしめでたし


参照

2009-03-18

[][][][][][]IDMSことはじめ:(2)IDMSの生成

IDMSことはじめ:(1)IDMSとは - 名もないテクノ手のつづき。

前回は、スニペットがIDMSというXMLフォーマットであることを説明しました。


IDMSの生成

今回は、Rubyの標準ライブラリであるREXMLを使って、IDMSを生成してみたいと思います。

#! /usr/bin/ruby -Ku

require "rexml/document"

my_str = <<EOF
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?aid style="50" type="snippet" readerVersion="6.0" featureSet="257" product="6.0(352)" ?>
<?aid SnippetType="PageItem"?>
<Document DOMVersion="6.0" Self="d">
	<Spread Self="ud0">
	</Spread>
</Document>
EOF

my_xml = REXML::Document.new my_str
my_Spread = my_xml.elements["/Document/Spread"]
my_Rectangle = my_Spread.add_element "Rectangle", {"Self"=>"ue5", "StrokeWeight"=>"0.5", "ItemTransform"=>"1 0 0 1 0 -421"}
my_Proerties = my_Rectangle.add_element "Properties"
my_PathGeometry = my_Proerties.add_element "PathGeometry"
my_GeometryPathType = my_PathGeometry.add_element "GeometryPathType", {"PathOpen"=>"false"}
my_PathPointArray = my_GeometryPathType.add_element "PathPointArray"
my_PathPointArray.add_element "PathPointType", {"Anchor"=>"50.25 100.25", "LeftDirection"=>"50.25 100.25", "RightDirection"=>"50.25 100.25"}
my_PathPointArray.add_element "PathPointType", {"Anchor"=>"50.25 299.75", "LeftDirection"=>"50.25 299.75", "RightDirection"=>"50.25 299.75"}
my_PathPointArray.add_element "PathPointType", {"Anchor"=>"199.75 299.75", "LeftDirection"=>"199.75 299.75", "RightDirection"=>"199.75 299.75"}
my_PathPointArray.add_element "PathPointType", {"Anchor"=>"199.75 100.25", "LeftDirection"=>"199.75 100.25", "RightDirection"=>"199.75 100.25"}
print my_xml

正直いって、XMLを手で書くのと手間は変わりません(w

あと、テスト中に気がついたのですけれど、このDOM階層が多少間違っていようと、要素名が間違っていようと、一切エラーはでないようでした。

ただ、ちゃんと図形にならないだけ^^

生成したXMLは、チェックしないといけないです。どうやって? Relax NGスキーマを使って。つづく...か?

参照

REXML API document (ja)

RubyでXML操作

2009-03-10

[][][][]IDMSことはじめ:(1)IDMSとは

IDMSとは...

IDMSとは、IDMLの単一ファイルバージョンです。要するにスニペットですが、InDesign CS3のそれとは大きくフォーマットが変わりました。すべてのページアイテムが、ひとつのファイルの中でアイテムや属性値、またはコンテンツとして表現されています。以前のスニペットフォーマットから、独自(で秘密裏)なオペレータが消え、(IDML同様)基本モデルにScripting DOMを採用して、よりXMLらしくなりました。IDMLとは違い、外部ファイル参照もありませんし、パッケージ(zipping)も不必要です。


IDMSの利用価値

IDMSはあらゆるページアイテムをXMLで完全に表現できます。しかし、ドキュメントの生成やページの生成はできません(そうした用途にはIDMLを使ってください)。

IDMSはどのような用途に使えるでしょうか? テキストの差し替えはもちろん、オブジェクトの配置調整ができる動的な小組みを作ったりできるかもしれません。いままでのXML処理やタグ処理でも可能なこともありますが、オブジェクト単位でさらに細かいコントロールができるでしょう。

重要なのは、IDMSがXMLであり、テキストであるってことです。そこには、スタンダードなツールでオブジェクトをコントロールできる(かもしれない)未来が待っています。


IDMSの作り方

最初は、ごく単純な図形から始めてみます。例として下記のような長方形をInDesign上で作りました。

f:id:seuzo:20090309221543p:image

IDMSの作り方は簡単です。スニペットを作ればいいのですから、選択アイテムをデスクトップ上にドラッグ&ドロップするだけです。中身はテキストエディタなどで直接見られます。

f:id:seuzo:20090309223025p:image

簡単な長方形なのに、200行以上あります。目が回りますね。余分な所を削って、少しダイエットさせてみましょう。


いろいろいじるそしてはまる

簡単な図形なのに、こんなにたくさんのXMLが生成されるのは、レイヤー情報やスォッチ情報、オブジェクトスタイルや、段落スタイルまですべての設定が書き出されているからです。フルコースのレシピがすべて書いてあるようなものです。欲しいのは単品のレシピだけなので抜き出してみましょう。

基本的に書かれていない値はデフォルト値が使われるようなので、Rectangleオブジェクトまで大胆にカットします。属性なども(デフォルトでOKなら)カットします。とりあえずこれで21行になりました。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?aid style="50" type="snippet" readerVersion="6.0" featureSet="257" product="6.0(352)" ?>
<?aid SnippetType="PageItem"?>
<Document DOMVersion="6.0" Self="d">
	<Spread Self="ud0">
		<Rectangle Self="ue5" StrokeWeight="0.5" ItemTransform="1 0 0 1 -82 -14.857142857142833">
			<Properties>
				<PathGeometry>
					<GeometryPathType PathOpen="false">
						<PathPointArray>
							<PathPointType Anchor="132.25 -305.83773903185715" LeftDirection="132.25 -305.83773903185715" RightDirection="132.25 -305.83773903185715"/>
							<PathPointType Anchor="132.25 -106.33773903185715" LeftDirection="132.25 -106.33773903185715" RightDirection="132.25 -106.33773903185715"/>
							<PathPointType Anchor="281.75 -106.33773903185715" LeftDirection="281.75 -106.33773903185715" RightDirection="281.75 -106.33773903185715"/>
							<PathPointType Anchor="281.75 -305.83773903185715" LeftDirection="281.75 -305.83773903185715" RightDirection="281.75 -305.83773903185715"/>
						</PathPointArray>
					</GeometryPathType>
				</PathGeometry>
			</Properties>
		</Rectangle>
	</Spread>
</Document>

実際に、このファイルをInDesign内に配置すれば、元と同じ図形ができます。

IDMSはIDMLと同様、DOM構造や属性値、Properties内のタグ名がスクリプトのそれに似せてあります。スクリプトを書く方ならば、だいたいどんな感じか想像ができるでしょう。

xml宣言の「standalone="yes"」はなぜか省略不可です。スニペットを表す2〜3行目も省略できませんでした。

PathPointの座標値はすべてを"x y"で表しているようです。でもあれ? 座標値が少しヘンです。どうやらRectangleの中のItemTransform属性が座標を既定する行列マトリックスらしいのでした。まとりっくすイキナリキタワ〜!

とりあえず今日は電卓を叩いて再計算しておきます。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?aid style="50" type="snippet" readerVersion="6.0" featureSet="257" product="6.0(352)" ?>
<?aid SnippetType="PageItem"?>
<Document DOMVersion="6.0" Self="d">
	<Spread Self="ud0">
		<Rectangle Self="ue5" StrokeWeight="0.5" ItemTransform="1 0 0 1 0 -421">
			<Properties>
				<PathGeometry>
					<GeometryPathType PathOpen="false">
						<PathPointArray>
							<PathPointType Anchor="50.25 100.25" LeftDirection="50.25 100.25" RightDirection="50.25 100.25"/>
							<PathPointType Anchor="50.25 299.75" LeftDirection="50.25 299.75" RightDirection="50.25 299.75"/>
							<PathPointType Anchor="199.75 299.75" LeftDirection="199.75 299.75" RightDirection="199.75 299.75"/>
							<PathPointType Anchor="199.75 100.25" LeftDirection="199.75 100.25" RightDirection="199.75 100.25"/>
						</PathPointArray>
					</GeometryPathType>
				</PathGeometry>
			</Properties>
		</Rectangle>
	</Spread>
</Document>

ナニがすっきりしたかというと、PathPointをドキュメントの左上原点からUIと同じ座標で書けたことです。で、ItemTransformですが、「idml-specification.pdf」のP76によりますと座標はスプレッドの中心にありますので、A4ドキュメントですとy方向に-421ptズラすズラ。ということです。IDMSの位置記憶というのはスプレッド中心から相対量だったわけですね。


もうひとつだけ例を示しておきます。円図形に平アミをかぶせてみました。

f:id:seuzo:20090226000429p:image

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?aid style="50" type="snippet" readerVersion="6.0" featureSet="257" product="6.0(352)" ?>
<?aid SnippetType="PageItem"?>
<Document DOMVersion="6.0" Self="d">
	<Color Self="Color/Black" Model="Process" Space="CMYK" ColorValue="0 0 0 100" />
	<Spread Self="ud0">
		<Oval Self="u13b" FillColor="Color/Black" FillTint="12" StrokeWeight="0.5"  ItemTransform="1 0 0 1 0 -421">
			<Properties>
				<PathGeometry>
					<GeometryPathType PathOpen="false">
						<PathPointArray>
							<PathPointType Anchor="205 182" LeftDirection="170 182" RightDirection="240 182"/>
							<PathPointType Anchor="270 116" LeftDirection="270 150" RightDirection="270 80"/>
							<PathPointType Anchor="205 52" LeftDirection="240 52" RightDirection="170 52"/>
							<PathPointType Anchor="140 116" LeftDirection="140 80" RightDirection="140 150"/>
						</PathPointArray>
					</GeometryPathType>
				</PathGeometry>
			</Properties>
		</Oval>
	</Spread>
</Document>

実はよくわかっていない

ということです。

少しづつやっていれば、見晴らしのいい場所にいけるんだろうか... ということで、時間があればちょっとづつ続けてみようと思います。もちろん、rubyでクラスを書いてくれるような神を熱烈待望しつつ。