tamagro.net/spelamSpelam 0.37 User's Guide ▶Rule File Format

Spelam Rule File Specification

DRAFT 2018-05-07

Spelamはウェブブラウザ上で動作する標本ラベル作成ツールである。 Spelamはルールファイルを記述することにより かなり自由にレイアウトすることができる。 本ドキュメントはそのルールファイルの仕様を定義したものである。


目次


1. はじめに

Spelamはブラウザのレンダリング機能を利用して 標本ラベルを自動組版するシステムである。 以下のような機能を有している。

1.1 簡単な例

ルールファイルの簡単な例を示す。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 <?xml version="1.0" encoding="utf-8"?>
 <spelam
    xmlns="urn:uuid:43d584cc-5578-4a89-826b-f0ce4c0f96c0"
    xmlns:s="urn:uuid:43d584cc-5578-4a89-826b-f0ce4c0f96c0"
    xmlns:h="http://www.w3.org/1999/xhtml"
    version="1.00">
  <rule name="Pinned Specimen Label" scale="10">
   <source>
    <field name="locality"/>
    <field name="dateCollected"/>
    <field name="collectedBy"/>
   </source>
   <style scale="10"><![CDATA[
    .card{
     width: 22mm;
     height: 16mm;
     box-sizing: border-box;
     padding: 1mm;
     font-size: 4pt;
     white-space: normal;
     line-height: 1.5;
     outline: solid 0.2pt black;
     outline-offset: -0.2pt;
    }
   ]]></style>
   <h:div class="card">
    {{locality}}
    {{dateCollected}}
    {{collectedBy}}
   </h:div>
  </rule>
 </spelam>

※ namespaceはuuidでいいのかな?

1-6行目
基本的にこの通り書く。 名前空間接頭辞は何でも良いのだが本ドキュメントでは's'と'h'を使用している。
7-31
一つのruleの定義。 ruleはいくつか書いてよく、メニューから選択することができる。
8-12
データファイルのフィールド名を宣言する。 CSVファイルのヘッダ行のフィールド名に対応。
13-25
CSSスタイル。
26
'h:div'はhtmlのdiv要素。
27-29
{{field-name}}でデータレコードの対応するフィールドが参照できる。

以下にデータファイルの例を示す。 データファイルのフォーマットはこちら

CSVの場合はヘッダ行が必須で、 フィールド名は ルールファイルのfield nameで宣言する必要があり(9-11)、 変数によって参照することができる(24-26)。

1
2
3
locality,dateCollected,collectedBy
Japan,12.xi.2014,J. Doe
Japan,5.ii.2016,J. Smith

これらのルールファイルとデータファイルを合わせてビルドを行えば、 以下のような2レコード分の標本ラベルが生成される。

実際とは少し違う

 <style>
  .card{
   width: 22mm;
   height: 16mm;
   box-sizing: border-box;
   padding: 1mm;
   font-size: 4pt;
   white-space: normal;
   line-height: 1.5;
   outline: solid 0.2pt black;
   outline-offset: -0.2pt;
  }
 </style>
 <div class="card">
  Japan 12.xi.2014 J. Doe
 </div>
 <div class="card">
  Japan 5.ii.2016 J. Smith
 </div>

この結果をブラウザで確認しブラウザから印字することで ラベルを作ることができる。

1.4 定数と変数

データレコードの各フィールドは変数によって参照することができる。 フィールド名はルールファイルfield要素で宣言しておく。 変数の参照は{{name}}で行う。 変数の参照は文字列の書けるコンテンツ内や属性内に置くことができる。

 <source>
  <field name="country" />  <!-- データファイルのフィールド宣言 -->
 </srouce>
 <h:div>
  {{country}} <!-- 変数の参照 -->
 </h:div>

変数はlet要素を使って定義することもできる。 letについては8章を参照されたい。

一部の属性は定数であること(データレコードに依存しない)が要求される。

変数名、style要素の内容、script要素の内容、rule名、ruleのスケール等

定数はconst要素で定義できる。

変数名

変数の名前は英字もしくは2バイト文字で始めることとする。

/^[A-Za-z\u0080-\uffff][A-Za-z_0-9\u0080-\uffff]*$/

1.4.1 変数あるいは定数の参照

変数や定数は変数名を2重ブレースで囲むことで参照できる。

 {{name}}

変数の参照は属性値とコンテンツ内の両方で使うことができる。

 <h:a href="{{url}}">{{name}}</h:a>

未定義の変数や定数を参照するとコンパイルエラーが発生する。

コンテンツ中の文字列は変数参照で分離される

以下のようにコンテンツ内に文字列と変数参照と子要素が含まれている場合、

 <hoge>abc{{v1}}def<uhyo>ghi</uhyo>jkl</hoge>

これらの要素は同じレベルとして扱われる。

 "abc", {{v1}}, "def", <uhyo>ghi</uhyo>, "jkl"

以下のように書いたのと同じ

parseMode="program"は空白を無視する

 <hoge parseMode="program">
  <text>abc</text>
  <text>{{v1}}</text>
  <text>def</text>
  <uhyo><text>abc</text></uhyo>
  <text>jkl</text>
 </hoge>

これは通常あまり関係ないが、 seriesなどでは 関係してくる場合がある。

1.4.2 変数の文字列化

変数にはlet文を使うとhtml要素もしまうことができる。 この変数をもし属性文字列中で参照した場合には文字列に変換される。 その処理方法は、 子孫要素に渡ってコンテンツ部分だけを取り出して連結したものとなる。

1
2
 <let name="hoge"><h:span><h:i>hoge</h:i> uhyo</h:span></let>
 <h:span title="{{hoge}}" ></h:span>  <!-- -> 'hoge uhyo' --> 

1.4.3 組み込み変数

{{}}
null 次節を参照。
lb, leftbrace
'{{'
rb, rightbrace
'}}'
empty
空文字列""。属性の場合は""と書ける。
recordNumber
レコード番号。1オリジン。

1.5 null

ある情報に付随する文字列があったとする。 例えば、標高の前に'alt. 'を付加したかったとする。

1
2
3
4
 <source>
  <field name="elevation" />
 </source>
 <text>alt. {{elevation}}</text>

これだと標高データがあるときはいいが、データがなかったときに 'alt.'だけ出力されてしまう。

alt. 1000m
alt.

これをif文なしでうまく処理するためにnullという概念を導入する。 以下の例でseries要素は内容が一つでもnullなら全体をnullにするので、 'alt. 'も生成されない。

1
2
3
4
5
6
7
 <source>
  <field name="elevation"/>
 </source>
 <series>
  <text>alt. </text>
  <text>{{elevation}}</text>
 </series>

1.5.1 文字列中のnull

  • 文字とnullが連結されるとき、nullは空文字""として扱われる。
  • 文字列中にnullしかない場合は、全体がnullになる。
  • ただし属性値""は内部的に空の文字列""に変換される。
属性値 内部値(Javascriptでの値)
"" ""
"{{}}{{}}" undefined
"a{{}}" "a"

1.5.2 コンテンツ中のnull

listMode属性によって動作が異なる。

2. 基本構造

2.1 spelam

一番外側に一つだけ書く。

1
2
3
4
5
6
7
<spelam 
 xmlns="urn:uuid:43d584cc-5578-4a89-826b-f0ce4c0f96c0"
 xmlns:s="urn:uuid:43d584cc-5578-4a89-826b-f0ce4c0f96c0"
 xmlns:h="http://www.w3.org/1999/xhtml"
 version="1.00" >
 ...
</spelam>

2.2 rule

spelamのすぐ内側に複数書ける。

例えば、 ピン刺し標本(?, pinned specimen?)、 液浸標本(vial specimen)、 スライド標本(slide specimen) などで別のルールを用意しておくと、 実行時にメニューから選択できる。

1
2
3
 <rule name="Microscope Slide Label" scale="10">...</rule>
 <rule name="Pinned Specimen Label" scale="10">...</rule>
 <rule name="Vial Specimen Label" scale="10">...</rule>

2.2.1 name

メニューに表示される名前。

任意の文字列。必須。定数。

2.2.2 scale

昆虫の標本ラベルは通常3pt~4pt程度の小さな文字が使用される。 このような小さなサイズはブラウザで制限されていて使えないし、 仮に使えたとしても割付が汚くなる(整数で処理されているもよう)。 そこで、内容を大きく作ってから、 全体を縮小している(cssのtransform機能を使う)。 このときのスケール。

例えばscale="10"とすると、 全体を1/10に縮小するので 内側は10倍の単位30pt〜40ptの大きさで作れる。

あまり大きい値を指定するとブラウザによっては問題を生ずるかもしれない。 10ぐらいが適当?

デフォルトは1。定数。

2.3 source

データファイルの使用するフィールド名を列挙する。 ここで指定した名前は変数として参照可能になり、 テンプレート内の{{name}}で埋め込むことができる。

1
2
3
4
5
 <source>
  <field name="locality"      />
  <field name="dataCollected" />
  <field name="collectedBy"   />
 </source>

2.3.1 csvDelimiter

未対応

現在ファイルの先頭から以下の文字を検索し 最初に見つかったものを区切り記号にしている。

"," ";" "|" tab

2.4 field

source要素の内側に書く。

  <field name="country" default="Japan" />

2.4.1 name

フィールド名を指定する。 ここで指定した名前で参照することができる。

名前規則は変数名と同じ。

必須。定数。

2.4.2 from

フィールド名を変更したい場合に使う。 fromはデータファイルのフィールド名。 nameはルールファイルで使う名前。

1
 <field name="elevation" from="altitude" />

オプション。定数。

2.4.3 default

フィールドが未定義であった場合や空の文字列''であった場合に 標準ではnullが使用される。 これを別の文字列に変換したい場合にdefault属性を使う。

1
 <field name="country" default="Japan" />

オプション。定数。

2.5 部品(コンポーネント)

ruleのコンテンツとして複数の部品を並べることができる。 部品にはhtml要素や文字列とspelam独自のものがある。 以下の例では、h:div, h:br, text, join, latitude, longitudeなどが 部品である。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 <rule>
  <h:div><join>
   <text><h:br></text>
   <join>
    <text>, </text>
    <list>
     <text>{{country}}</text>
     <text>{{pref}}</text>
     <text>{{city}}</text>
    </list>
   </join>
   <join>
    <text>, </text>
    <list>
     <latitude>{{latitude}}</latitude>
     <longitude>{{longitude}}</longitude>
    </list>
   </join>
  </join></h:div>
 </rule>

2.6 html要素等

部品としてhtml要素が書ける。はず...

名前空間接頭辞を付加するか もしくはデフォルト名前空間をxhtmlにする必要がある。 この文書では'h'を付加している。

1
2
3
4
5
6
7
8
 <spelam 
    xmlns="urn:uuid:43d584cc-5578-4a89-826b-f0ce4c0f96c0"
    xmlns:h="http://www.w3.org/1999/xhtml"
  >
  <rule>
   <h:div> ... </h:div>
  </rule>
 </spelam>

textboxを使わずに文字を書く場合

ruleの下にhtml要素を置いてその中に文字列を置く場合、 スタイルでwhite-space: normal;を指定する必要がある。

※カードを複数枚横に並べられるようにwhite-space: nowrap;を指定しているが この属性は子要素に引き継がれるため。

textboxの場合はプログラム内で設定している。

html以外

簡単なsvgはOKだった。

※ 未調査

html以外にもブラウザでレンダリング可能な要素なら書けるはずだが

MathMLはなぜかダメだった。htmltextでは大丈夫。

書けない属性

※ 詳しく調べてない。

テンプレートは複製されるためidは書けない。 以下のように別なIDが生成されるようにすれば可能だが、 どういう用途ががあるのかはわからない。

id="hoge-{{recordNumber}}"

spelamの共通属性

名前空間を指定するれば書ける。

1
2
3
 <h:div s:mode="list">
  ...
 </h:div>

変数

Spelamの変数が使える。

1
  <h:a href="{{URL}}">{{title}}</h:a>

2.7 htmltext

前段のシステムでhtmlテキストを生成できるときに使う。

1
 <htmltext>{{remarkHtml}}</htmltext>

2.8 style要素

スタイルシートを埋め込むことができる。 書き方はXHTMLと同じ。 部品を書ける場所ならどこに書いてもよい。 複数書いても良くすべて連結されたスタイルシートが生成される。

1
2
3
4
5
6
7
8
9
  <style><![CDATA[
   .bold{ font-weight: bold; }
   .italic{ font-style: italic; }
   .big{ font-size: 1.4em; }
   .small{ font-size: 0.7em; }
   .small-caps{ font-variant: small-caps; }
   .nowrap{ white-space: nowrap; }
   .align-right{ text-align: right; }
  ]]></style>

定数であること。

2.8.1 scale

ruleで書いたように小さいサイズのフォントを扱うため 内部的に拡大して処理している。 したがってスタイルシートの値もそれに合わせて拡大する必要があるが オプションで変換できるようにした。

下の2つの例は同じスタイルを定義している。

1
2
3
4
5
6
  <style ><![CDATA[
   .card{ width: 220mm; height: 220mm; }
  ]]></style>
  <style scale="10"><![CDATA[
   .card{ width: 22mm; height: 22mm; }
  ]]></style>

オプション。定数。

3 共通属性

共通属性は名前空間接頭辞をつければ 外部要素にも指定できる。

 <h:div s:mode="list">
  ...
 </h:div>

3.1 parseMode属性

コンテンツ内の文字列の扱い。

parseMode = "text" | "program"

"text"の場合は文字列をそのまま扱う。 "program"の場合は空白を無視し空白以外の文字列はエラーとする。

デフォルトはリスト関連部品とブロック部品は"program"、 外部要素(h:div等)、テキスト部品は"text"。 

オプション。定数。

補足

HTMLの場合、コンテンツ内の文字はデータとして扱われる。 これはparseMode = 'text'に相当する。 インデントを保ちつつ空白を入れないようにしたい場合が時々あり、 その場合は以下のように少し妙な書き方をしないといけない。

1
2
3
4
  <h:div
   ><text>{{country}}</text
   ><text>{{stateProvince}}</text
  ></h:div>

parseMode="porogram"を指定すると空白は無視されるので 以下のようにすっきり書ける。

1
2
3
4
 <h:div s:parseMode="program">
  <text>{{country}}</text>
  <text>{{stateProvince}}</text>
 </h:div>

3.2 listMode属性

コンテンツ内のnullの扱い。

listMode = "list" | "array" | "series"

デフォルトは通常"list"にしておくか。 (array, series部品以外)

list
コンテンツ内のnullを無視する。list参照。
array
コンテンツ内のnullを保存する。array参照。
series
コンテンツ内にnullがあったら全体をnullにする。series参照。

3.3 mode属性

parseModeとlistModeを同時に設定する。

mode = "text" | "list" | "array" | "series"

設定される値は以下の通り。

mode parseMode listMode
text text list
list program list
array program array
series program series

3.4 generate属性

コンテンツがnullの場合全体を生成しない。 ブロックを生成する部品で有効。

テキスト部品は?

generate = "always" | "ifNotNull" | "none"

always
常に生成する
ifNotNull
nullの場合は生成しない
none
常に生成しない。未対応

以下の例では、{{contents}}がnullの場合、 h:divを生成しない(nullを返す)。

1
 <h:div s:generate="ifNotNull">{{contents}}</h:div>

3.5 class属性

htmlのclassと同様。 spelam要素もclass属性を別に持っており、 名前空間接頭辞は不要で単にclass="hoge"のように書く。

有効なのは外部要素、ブロック部品テキスト部品に限る。 text部品でclassを指定した場合はspanを生成する。

1
2
3
4
5
6
7
  <rule>
   <style><![CDATA[
    .bold { font-weight: bold }
    .small-caps{ font-variant: small-caps }
   ]]></style>
   <h:span class="bold small-caps">{{collectedBy}}</h:span>
  </rule>

クラス名の名前の制限

   /^[a-z_\u0080-\uffff][a-z_0-9\-\u0080-\uffff]*
     (\s+[a-z_\u0080-\uffff][a-z_0-9\-\u0080-\uffff]*)*$/i

'slm-'で始まる名前は内部で使用しているので使わないように。

3.6 style属性

スケール処理されないので注意。 spelam部品もstyle属性を持っており、 名前空間接頭辞は不要で単にstyle="hogehoge"と書く。

有効なのは外部要素、ブロック部品テキスト部品に限る。

 <text style="font-variant:small-caps">{{collectedBy}}</text>

5 テキスト部品

デフォルト: parseMode="text", listMode="list"

通常はspanやdivのような構造を作らないが、 classかstyleが指定されたらspanを生成する。

1
2
 <text class="small-caps">{{collectedBy}}</text>
   <!-- == <h:span class="small-caps">{{collectedBy}}</h:span> -->

5.1 text

parseMode="program"のとき、文字列を書くために使う。

1
 <text>{{country}}</text>

5.2 date 部品

日付の体裁を整える場合に使う。 範囲の指定に対応している。

1
2
 <date inputFormat="ISO" format="d.rm.yyyy"
  >{{dateCollected}}</date>

内容の書き方はinputFormatに依存する。

5.2.1 inputFormat 属性

入力書式を"ISO", "DMY", "MDY"のいずれかで指定する。 デフォルトは"DMY"。

"DMY"

基本的には自動的に処理されるが、月が数字であった場合DMYと解釈する。 年は4桁の数字であること。

以下全て2018年3月15日の書き方。

  • 2018.3.15
  • 15 may 2018
  • may 15 2018
  • 15.iii.2018
  • 15 3 2018 → day month yearと解釈

範囲の区切りはハイフン類に限る。

"MDY"

"DMY"と同様だが月が数字であった場合にMDYと解釈する。 

  • 3 15 2018 → month day yearと解釈(値は見てない)
"ISO"

ISO8601規格の一部のみ対応している。

  • 2018-03-15
  • 20180315T23/16T07

5.2.2 format

出力フォーマット。 デフォルトは'd.rm.yyyy'。

  formatValue ::= ((dayFormat sep)? (mothFormat sep)? yearFormat
  dayFormat ::= 'd' | 'dd'
  monthFormat ::= 'rm' | 'RM' | 'Mon' | 'MON' | 'mon' | 'm' | 'mm'
  yearFormat ::= 'yyyy'
  sep ::= [^a-zA-Z0-9]+
dayFormat
  • d 1 - 31
  • dd 01 - 31
monthFormat
  • rm i - xii
  • RM I - XII
  • MON JAN .. DEC
  • mon jan .. dec
  • Mon Jan .. Dec
  • m 1..12
  • mm 01..12
yearFormat
  • yyyy 2018
sep

そのまま出力

  format="d RM yyyy" → 15 III 2018
  format="d.rm.yyyy" → 15.iii.2018
  format="yyyy" → 2018

5.2.3 範囲指定について

入力データの範囲記号は固定で DMY, MDYの場合 ハイフン類('-'|U+2010|U+2011)とする。 ISOの場合は規格どおり'/'とする。

出力フォーマットの範囲記号はU+2010固定としている。

オプション?

入力フィールドが開始日と終了日の2つに分かれている場合、 以下のように'-'(ISOの場合は'/')でつなげていただきたい。

1
2
3
4
5
  <source>
   <field name="dateStart"/>
   <field name="dateEnd"/>
  </source>
  <date>{{dateStart}}-{{dateEnd}}</date>

5.3 latitude, longitude 部品

緯度経度の体裁を整える場合に使う。

1
2
 <latitude format="DMS.1">{{latitude}}</latitude>
 <longitude format="DMS.1">{{longitude}}</logitude>

5.3.1 内容

緯度、経度情報。

入力データは緯度と経度が分離していてもよいしまとまっていてもよい。 まとまっている場合入力フォーマットは自動的に判別されるが、 NSEW記号が含まれない場合は','区切りであることとし、 緯度経度の順であると仮定する。 左側が緯度、右側が経度。 北緯および東経が正の数値で、南緯と西経が負の数値。

  35.795504, 138.389400
  -27.378054, 152.961500

NSEW記号が含まれていればかなり適当に書ける。

  35°47'45.1"N 138°23'21.9"E
  138°23'21.84"E 35°47'43.81"N
  35°47.23'N 138°23.56'E
  N35°47.23' E138°23.56'
  E138°23'21.84" N35°47'43.81"

5.3.2 format属性

出力フォーマット。デフォルトは'DMS'。

( 'DMS' | 'DM' | 'D' ) ( '.' decimalPlaces )?
decimalPlaces ::= [0-9]+

'DMS'は度分秒形式、'DM'は度分形式、'D'は度形式。 decimalPlacesは小数点以下桁数。 省略した場合、DMSの場合は0、DMの場合2、Dの場合は4とする。

以下の例では、DMS形式で小数点以下1桁まで表示される。

 format="DMS.1"

5.3.3 symbols属性

度分秒の単位記号として何を使うか。 度の記号はU+00B0(°)固定。

symbols="forComputing"|"forPrinting"

"forComputing"
アポストロフィーU+0027とクォーテーションマーク(U+0022)を使用する。
"forPrinting"
プライムU+2032とダブルプライムU+2033を使用する。
"forComputing" ° ' "
"forPrintig" ° ′ ″

5.4 scientificName 部品

文字列で与えられた学名を自動的にイタリック化する(italicize)。

1
 <scientificName>{{scinentificName}}</scientificName>

Actias aliena (Butler, 1879) → Actias aliena (Butler, 1879)

この機能は不完全なので使用する場合は注意すること。 後述するアルゴリズム参照。 だいたいうまくいくと思うが 場合によっては手動で指定する必要があるかもしれない。

手動で指定する場合は イタリックにする部分を開始文字と終了文字で囲む。

1
 /Actias/ /aliena/ (Butler, 1879)

データ中に開始記号が含まれていれば手動での指定となり、 なければ自動処理される。

5.4.1 italicIndicators属性

開始記号と終了記号を空白で区切って指定する。 複数文字でもよい。 デフォルトは"/"。

 italicIndicators="{ }"
 italicIndicators="(( ))"

開始と終了が同じ場合は一つで良い。 以下の2つは同じ。

 italicIndicators="/ /"
 italicIndicators="/"

5.4.2 symbols

記号を印刷用のものに変換する。

 symbols="" | "forPrinting"
""
なにもしない。
"forPrinting"
アポストロフィー、一重引用符、乗算記号を変換する。
アポストロフィー

ASCIIアポストロフィー0x27(')を Unicode 右引用符U+2019(’)に変換する。

一重引用符

※ 栽培種で使われる記号

引用符と考えられるASCIIアポストロフィー0x27(')を Unocodeの左右引用符 U+2018(‘), U+2019(’)に変換する

おそらくデーターベース中では 左引用符、右引用符、アポストロフィーも同じ記号(')が使われていると思う。

これを自動判別して処理するのだが うまくいくかどうか…

'の後ろに英小文字が来るのは名前として使われているため、

 't Hart

以下のようなパターンで処理している。

 \s\'[A-Z]
乗算記号

※雑種で使われる記号

ASCII小文字の'x'を乗算記号U+00d7(×)に変換する。

イタリック化アルゴリズム

栽培種の処理も行っているがここでは割愛する。 (正しいのかどうかもよくわかっていない)

[1] 種小名を探す

以下のパターンであり、

 \s*[a-z][a-z\-\u2010\u2011]*\s

以下のキーワードでないものを種小名とする。

  'subgenus', 'section', 'series',
  'x',
  'ex', 'et', 'in', 'lato', 'nec', 'non', 'sensu', 'strict',

[2] 種小名より左側の文字列に対して

[2.1] 属名

先頭から始まる英大文字で始まる名前を属名としてイタリック化する。

    ^[A-Z][a-z\-\u2010\u2011\.]*\s

'.'は以下のようなのを処理するのに入れてある。

Dianthus caryophyllus × D. plumarius

[2.2] 亜属名

続く()で囲まれた英大文字で始まる名前を亜属名としてイタリック化する。

    \(\s*[A-Z][a-z\-\u2010\u2011]*\s*\)

[2.3] その他

続く以下のキーワードの後ろの大文字で始まる名前をイタリック化する。

 cf. aff. genus gen. subgenus subgen. subg. section sect. series ser.

[3] 種小名をイタリック体で出力

[4] 種小名より後ろの文字列に対して

[4.1] 亜種名

種小名のすぐ後ろに以下のパターンがあった場合、

 \s*[a-z][a-z\-\u2010\u2011]*\s

以下のキーワードはイタリック化しないで出力。

  'subgenus', 'section', 'series',
  'x',
  'ex', 'et', 'in', 'lato', 'nec', 'non', 'sensu', 'strict',

以下のパターンを人名としてイタリック化しないで出力。

  'da', 'de', 'del', 'den', 'di', 'du',
  'la', 'le', 'ten', 'ter', 'van', 'von', 'zur'

それ以外は亜種名としてイタリック化して出力する。

[4.2] 亜種名より後ろは、'f.'などの修飾子の後ろの 小文字で始まる名前をイタリック化する。

 subsp. sub. ssp. var. forma f.

5.5 capitalize 部品

大文字化する。

 <capitalize>{{country}}</capitalize>

JavascriptのtoUpperCase()を使っている。 アクセント記号付き文字も大丈夫みたい。

6 リスト関連

リスト関連部品はそれ自体DOM要素を作らないので、 classやstyle属性の指定は無視される。

parseMode: "program"
listMode: 部品による

list, array, seriesはlistModeで指定した場合も同様な効果がある。

文字列リテラルは変数参照で分離される。 以下の例は

1
 <text listMode="list">c1{{v1}}<text>c2</text></text>

以下のように書いたのと同じ。

1
2
3
4
5
 <list>
  <text>c1</text>
  <text>{{v1}}</text>
  <text>c2</text>
 </list>

6.1 list

コンテンツ内のnull要素は捨てられる。 コンテンツ内の全ての要素がnullなら全体がnull。 ただし要素の指定がない場合は空の列を生成する。

 <list><text>a</text><text>{{}}</text><text>b</text></list> 
   <!-- JS:[ "a", "b" ] -->

 <list><text>{{}}</text><text>{{}}</text></list> 
   <!-- JS:undefined -->

 <list></list>  <!-- JS:[] -->

 <list/> <!-- JS:[] -->

parseMode = "program"
listMode = "list"

joinでデータフィールドが空のときに余計な','を生成したくない場合

1
2
3
4
5
6
7
8
9
 <join>
  <text>, </text>
  <list>
   <text>{{country}}</text>
   <text>{{pref}}</text>
   <text>{{city}}</text>
   <text>{{locality}}</text>
  </list>
 </join>

6.2 array

コンテンツ内のnull要素は保存される。

 <array><text>a</text><text>{{}}</text><text>b</text>
   <!-- JS:[ "a", undefined, "b" ] -->

 <array></array>
   <!-- JS:[] -->

parseMode = "program"
listMode = "list"

以下の例では空白だったフィールドの間にも', 'が生成される。 良い例が思い浮かばないが、','が必須な場合。

1
2
3
4
5
6
7
8
9
10
 <join>
  <text>, </text>
  <array>
   <text>{{country}}</text>
   <text>{{pref}}</text>
   <text>{{city}}</text>
   <text>{{locality}}</text>
  </array>
 </join>
 <!--  Japan, , , Mt. Fuji -->

6.3 series

コンテンツ内に一つでもnullが含まれていたら全体をnullにする。 すべての要素がnullでなければ結果はarrayやlistと同じ。

parseMode = "program" listMode = "series"

以下の例ではcollectedByがnullでなかった場合のみ、'coll. 'を付加する。

1
2
3
4
 <series>
  <text>coll. </text>
  <text>{{collectedBy}}</text>
 </series>

6.4 alternate

コンテンツ内の要素を順番に処理して、 最初にnull以外だったものを結果とする。 デフォルト値の指定などに使う。

parseMode = "program"

以下の例では{{country}}が空白だった場合に、'Japan'を生成する。 この例はfieldのdefaultも可能。

1
2
3
4
 <alternate>
  <text>{{country}}</text>
  <text>Japan</text>
 </alternate>

6.5 join

配列の要素を分離符で区切って連結したものを生成する。 コンテンツには2つの要素を書く。 最初の要素は分離符で2つ目の要素はリスト。 分離符はとくに制限はない(文字列でなくても良い)。 リストには通常array, list, seriesなどを使う。 listを使うと内容がnullであった場合、分離符は生成されないが、 arrayの場合は生成される。

1
2
3
4
 <join>
  {separator}
  {array}
 </join>

parseMode = "program"
listMode = "array"

1
2
3
4
5
6
7
8
 <join>
  <text>, </text>
  <list>
   <text>{{pref}}</text>
   <text>{{city}}</text>
   <text>{{locality}}</text>
  </list>
 </join>

separatorがnullの場合は、空列""として処理する。 arrayがnullの場合は、全体をnullとする。

7 ブロック

7.1 textbox

あふれ詰め込み機能(copy fitting)を持つ枠。

※用語がよくわからない。箱組というのも関係しそうだけど、 おそらく業界によって定義が違いそう。 英語はcopy fittingで良さそう。

あふれ詰め込みは 内容が枠の大きさの範囲内に収まるように、 文字の大きさや枠の大きさを調整する機能である。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 <style scale="10"><![CDATA[
  .collection-label{
   position: absolute;
   top: 1mm;
   bottom: 1mm;
   left: 1mm;
   right: 1mm;
   width: 18mm;
  }
 ]]></style>
 <textbox
   class="collection-label"
   minFontSize="3pt"
   maxFontSize="4pt"
   >
  <text ... />
  ...
 </textbox>

minWidth, maxWidth, minHeight, maxHeight, minFontSize, maxFontSize

枠の大きさと文字サイズ。 固定の場合は、スタイルで指定してもよい。 指定する場合は、minとmaxは両方を指定し単位は同じであること。 minとmaxは同じ値でもよい。 絶対単位(mm,pt等)の場合、ruleのscale属性が適用される。

構造

2重にdivが作成される。 クラス名を指定した場合は外側のdivに設定される。

 <div class="classname">
  <div>{{contents}}</div>
 </div>

アルゴリズム

文字は大きいほうがよく、枠は小さい方が良いとする。 一次元のパラメタ、評価値(e: 0<=e<=1)をを考え、 以下のような関数でフォントサイズと枠の大きさに対応付ける。 e=1は最も評価が良い状態で e=0は最も評価が悪い。

Fs(e) = maxFontSize*e + minFontSize*(1-e)
Wd(e) = minWidth*e + maxWidth*(1-e)
Ht(e) = minHeight*e + maxHeight*(1-e)

あるeにおけるFs(e)とWd(e)を元に 文字を割り付けた時の高さH(e)とすると、 H(e) <= Ht(e) となる最大のeを求める。

H(e)は必ずしも単調増加ではないが、大域的に単調であるので 2分法を用いて処理している。

e = 0で入らない場合はエラーとする。

7.2 transform

主に枠を回転する目的で使う。

CSSには変形の機能があるが、 大きさが可変の枠を変形したあとの大きさ 大きさを使って割り付けることがたぶんできない。 Javascriptを使って処理している。

1
2
3
 <transform rotate="-90deg">
  <textbox > ....</textobx>
 </transform>

7.2.1 rotate

回転する角度を指定する。 単位は"deg"しか対応していない。 正の値で時計回り、負の値を指定すると反時計回りに回転する。

7.2.2 scale, scaleX, scaleY

鏡像のために入れた。

倍率を指定してもよいが、 ruleのscale属性を反映している箇所は 自分で処理する必要がある。

構造

2重にdivが作成される。 クラスを指定した場合はは外側のdivに設定される。

 <div class="classname">
  <div>{{contents}}</div>
 </div>

処理方法

まず内容の大きさを先に求める。 その内容に指定した変形を掛ける。 変形されたものが収まるような最小の枠をその外側に生成する。

制限事項

  • textboxの内側には置けない

7.3 qrcode

MITライセンスのコードがあったので入れてみた。 信頼できるものなのかどうか調査したほうが良いと思うぞ。

1
2
3
4
5
6
7
  <style scale="10"><![CDATA[
   .qrcode{
    position: absolute;
    bottom: 1mm; left: 1mm; width: 5mm; height: 5mm;
   }
  ]]></style>
 <qrcode class="qrcode" correctLevel="M">{{specimenCode}}</qrcode>

7.3.1 コンテンツ

コードをしまう。 エンコーディングはUTF-8固定。 スペースもそのまま入るので、無駄なスペースを入れないように注意。

7.3.2 correctLevel 属性

qrcode規格のエラー訂正レベルを指定する。 デフォルトは'Q'。

  'L' | 'M' | 'Q' | 'H'

Hが最も高い。 エラー訂正レベルは高い方が信頼性も高いが、 パターンが複雑になるため小さい面積に印字するのは難しくなる。

8 宣言とscript

工事中

8.1 const

定数の宣言。 定数名は変数と同じように参照できる。 コンパイル時に評価され、値は常に文字列化される。 値として変数が出現した場合はコンパイルエラーになる。 また未定義の名前が出現した場合もコンパイルエラーとなる。

 <const name="name">value</const>

スコープ

定数名は一つ上の要素内でのみ有効。

 <textbox>
  <const name="hoge">...</const>
  <!-- このtextbox内でのみ有効 -->
 </textbox>

8.2 let

変数の宣言。 スコープは定数と同じ。

 <let name="name">value</let>

8.3 call

Javascript関数の呼び出し。 scriptで定義した関数を呼び出せる。

1
 <call name="f" arg="..">...</call>

8.3.1 name

8.3.2 arg

任意の属性を指定できる。

8.4 script

関数の実体をJavascriptで定義する。

書き方の詳細はSpelam関数(工事中)を参照。

1
2
3
4
5
6
7
8
 <script><![CDATA[
   this.defineFunction('capitalize',function(attributes,contents){
    let str = this.docToString(contents);
    if ( str !== undefined ) {
     return str.toUpperCase();
    }
   });
 ]]></script>

tamagro.net/spelamSpelam 0.37 User's Guide ▶Rule File Format
©2018 A. Koguchi