プロパティリスト(Property List)は永續化(シリアライズ)の爲の手段である。Windows ユーザでも iTunes ライブラリを展開したものは、ここを覗く人なら居るかも知れない。嚴密にはプログラミング言語ではないが、Cocoa ではあまりにも重要なので扱ふことにする。

目次

プログラミング言語/Objective-C

永續化對稱クラス

  • NSString
  • NSNumber(シリアライザは int か float か bool かを區別する)
  • NSDate
  • NSData
  • NSArray
  • NSDictionary

以上の物とそのサブクラスが對稱となる。以外はプロパティリストとして保存できない。またコレクションクラス(配列と辭書)の場合は格納するオブジェクトもこの基準に沿はねばならない。

Cocoa API

Cocoa では Foundation フレームワークに plist 專用のクラスやメソッドが用意されてゐる。NSPropertyListSerialization クラスである。

NSPropertyListSerialization クラス

次の三つのクラスメソッドが定義される。

###	NSPropertyListSerialization Class: Tasks
#	Serializing a Property List
+ dataFromPropertyList:format:errorDescription:
#	Deserializing a Property List
+ propertyListFromData:mutabilityOption:format:errorDescription:
#	Validating a Property List
+ propertyList:isValidForFormat:

NSData 形式でテキストを渡しオブジェクトを復元して返すのが propertyListFromData メソッドである。 propertyList メソッドは復元可能かを調べる爲に使用する。dataFromPropertyList はオブジェクトインスタンスを永續化したテキストを NSData に格納して返す。エンコードは XML ならば UTF-8 になる。

+ (id)propertyListFromData: (NSData *)data
 mutabilityOption:(NSPropertyListMutabilityOptions)opt
 format:(NSPropertyListFormat *)format
 errorDescription:(NSString **)errorString
+ (BOOL)propertyList:(id)plist
 isValidForFormat:(NSPropertyListFormat)format
+ (NSData *)dataFromPropertyList:(id)plist
 format:(NSPropertyListFormat)format
 errorDescription:(NSString **)errorString

引數はこのやうになる。NSPropertyListFormat と NSPropertyListMutabilityOptions は以下の定數をとる。

NSPropertyListMutabilityOptions:
  NSPropertyListImmutable
  NSPropertyListMutableContainers
  NSPropertyListMutableContainersAndLeaves
NSPropertyListFormat:
  NSPropertyListOpenStepFormat # ASCII Property List
  NSPropertyListXMLFormat_v1_0 # XML Property List
  NSPropertyListBinaryFormat_v1_0 # Binary Property List

NSPropertyListFormat は種類の指定であり、NSPropertyListFormat は復元方法である。NSPropertyListFormat を引數にとる propertyList メソッドはどの種類に適合するかを判斷する訣である。dataFromPropertyList は通知された種類に永續化を試み、propertyListFromData は通知された種類に解する。

propertyListFromData で指定する NSPropertyListMutabilityOptions は變更可能なオブジェクトとするか否かであり、通常は NSPropertyListImmutable である。NSPropertyListMutableContainers は變更可能なオブジェクトであるが、その内部構成までは變更可能ではないインスタンスとして返す。NSPropertyListMutableContainersAndLeaves は全てのインスタンスが變更可能なオブジェクトとなる。

NSArray, NSDictionary, NSString クラス

これらには特別に次のメソッドが與へられてゐる。

###	NSArray Class: Tasks
# Creating an Array
+ arrayWithContentsOfFile
+ arrayWithContentsOfURL
# Initializing an Array
- initWithContentsOfFile
- initWithContentsOfURL
# Creating a Description
- writeToFile
- writeToURL
###	NSDictionary Class: Tasks
# Creating a Dictionary
+ dictionaryWithContentsOfFile
+ dictionaryWithContentsOfURL
# Initializing an NSDictionary Instance
- initWithContentsOfFile
- initWithContentsOfURL
# Storing Dictionaries
- writeToFile
- writeToURL
### NSString Class: Tasks
Converting String Contents Into a Property List
– propertyList  
– propertyListFromStringsFileFormat  

NSArray 及び NSDictionary には復元と保存の兩樣のインスタンス乃至クラスメソッドがある。

NSData や NSString の場合 writeTo*** は中身を出力する爲のメソッドであり、NSString に關しては出力するファイルエンコーディングを指定して變換し保存する物だが、NSArray と NSDictionary は plist として保存する爲のメソッドになる。

NSString の propertyList は自身を Property List として解析しインスタンスを生成しそれを返し、propertyListFromStringsFileFormat は strings形式(cf. ASCII形式)として自身を解析して NSDictionary を返す。

Apple Script での利用

Mac OS X v10.5 から讀み書きができるやうになります。

NeXTstep 形式プロパティリスト(OPENSTEP、ASCII形式)

この形式の利點は人がみて讀みやすい所にある。ただし、古い形式であるため NSDate は NSString と、眞僞値は數値との區別がつかなくなる。

クラス記法備考
NSStringstring"string"値が英數字及び「_」のみの時はダブルクオート無し。一部エスケープされる
NSNumberYES(bool)1----
NSNumberNO(bool)0----
NSNumber20(int)20----
NSNumber2.0(float)2.0----
NSDate@referencetime"YYYY-MM-DD HH:mm:ss ±XXXX"ISO に基づくが、これは恐らく description の値
NSData0xAD238FE8321.....<10101101 00100011 0011.....>バイナリは二進數に變換され、8bit=1byte ごとに半角スペースが入る
NSArray[obj,obj,.....,obj](<obj>, <obj>, ...., <obj>)<obj>の記法は各々のクラス依存
NSDictionary[key=>obj,key=>obj]{<key>=<obj>; <key>=<obj>; }<obj>の記法は各々のクラス依存で、<key>はNSStringに同じ

NSString のエスケープ

Unicode のバイナリ値がそのまま出力される。やうは UTF-16 で出力する。「あ」は2ビットコードであり「U+3042」である。これは「\U3042」と出力される。改行コードは LF は「\n」に置換されるが、CR はそのままである。タブは「\t」に変換され、ダブルクオートもまた「\"」となる。バックスラッシュは重ねることになる。嚴密には、2ビット以上のUnicodeであるとバイナリ値へエスケープされるらしい。

文字エスケープ備考
aa値が英數字及び「_」のみの時はダブルクオートが無く、また左記に同じ。ASCIIの他は次のやうになる
\U3042Unicode は U+3042
タブ\t----
改行(LF)\n----
改行・復歸(CR)(そのまま)----
ダブルクオート(")\"----
バックスラッシュ(\)\\----

コレクションの改行

コレクションはその文字數を一列に並べた時に78バイトを超過すれば、アイテムごとに改行することになる。

{
    "Application Version" = "8.0.1"; 
    Features = 5; 
    "Library Persistent ID" = XXXXXXXXXXXXXXXX; 
    "Major Version" = 1; 
    "Minor Version" = 1; 
    "Music Folder" = "/Users/XXX/Music/iTunes/iTunes%20Music/"; 
    Playlists = (
        {
        ..... 
        },
    .......
    );
}

セミコロン(;)及びコロン(,)は必ず半角スペースを一つ後置する。これはダブルクオートで括らない場合への對處。コレクションの要素がこれらで區切られぬ場合、パーサはエラーを發する。なほ NSArray の最後の項目にはコロンが無いのが標準だが、うつかり附けてもきつちり認識される。

コメント

コメントは次の三つの形式を許可する。

  • //
  • #
  • /* */

お馴染みであらう。前者二項は改行、後者一項は「/*」で始まり「*/」で終はるまでがコメントと看做される。

strings の爲の擴張

strings は Localizable.strings など、NSBundle クラス等で取得しローカライズ辭書で使用される、UTF-16 でエンコーディングされた書類である。これのためにパーサは NSDictionary がルートである時に限り、ルート要素の NSDictionary には鍵括弧を必要としない。

よつて先程示した ASCII の plist は次のやうでも同樣に解釋されることになる。

"Application Version" = "8.0.1"; 
Features = 5; 
"Library Persistent ID" = XXXXXXXXXXXXXXXX; 
"Major Version" = 1; 
"Minor Version" = 1; 
"Music Folder" = "/Users/XXX/Music/iTunes/iTunes%20Music/"; 
Playlists = (
    {
    ..... 
    }, /* これは註釋 */
.......
); # これも註釋
// これもさうである

Localized.strings では普通使はないけれど、他の NSArray などのコレクションをこれは要素として持つ事ができる。

XML 形式プロパティリスト

あまりこれといつた面白みがない。まづ手始めに DTD があるのでそれをみてみよう。/System/Library/DTDs/PropertyList-1.0.dtd にインストールされてゐる。http://www.apple.com/DTDs/PropertyList-1.0.dtd からも參照できる。

Property List - Document Type Definition(plist DTD)

<!ENTITY % plistObject "(array | data | date | dict | real | integer | string | true | false )" >
<!ELEMENT plist %plistObject;>
<!ATTLIST plist version CDATA "1.0" >

<!-- Collections -->
<!ELEMENT array (%plistObject;)*>
<!ELEMENT dict (key, %plistObject;)*>
<!ELEMENT key (#PCDATA)>

<!--- Primitive types -->
<!ELEMENT string (#PCDATA)>
<!ELEMENT data (#PCDATA)> <!-- Contents interpreted as Base-64 encoded -->
<!ELEMENT date (#PCDATA)> <!-- Contents should conform to a subset of ISO 8601
      (in particular, YYYY '-' MM '-' DD 'T' HH ':' MM ':' SS 'Z'.  Smaller units may be omitted with a loss of precision) -->

<!-- Numerical primitives -->
<!ELEMENT true EMPTY>  <!-- Boolean constant true -->
<!ELEMENT false EMPTY> <!-- Boolean constant false -->
<!ELEMENT real (#PCDATA)> <!-- Contents should represent a floating point number matching
          ("+" | "-")? d+ ("."d*)? ("E" ("+" | "-") d+)? where d is a digit 0-9.  -->
<!ELEMENT integer (#PCDATA)> <!-- Contents should represent a (possibly signed) integer number in base 10 -->

この DTD の素晴らしい點はこれをみれば Foundation の六つのクラスに必要なことと役割がある程度わかることである。

エレメント對應クラス屬性備考
plist----エンティティ plistObject を一つversion屬性は version="1.0" のみ許容
arrayNSArrayエンティティ plistObject を0個以上--------
dictNSArrayエレメント key とその次にエンティティ plistObject 、この組を0個以上--------
key----文字列----強いて言へば對應クラスは NSString
stringNSString文字列--------
dataNSData文字列----ただし書きには Base64 encode濟 であるとある
dateNSDate文字列----ISO 8601 に基づく
trueNSNumber--------値を取てはならない
falseNSNumber--------値を取てはならない
realNSNumber文字列----ただし書き正規表現に從ふ文字列
integerNSNumber文字列----10進數のみ

エンティティ plistObject は plist タグと key タグを除く全てになる。普通はしない DTD を定義したのは可視性の向上などにあると思はれる。この單純な(けれど冗長な)コーディングによつて、プログラマは xml を開いてみただけで何がシリアライズされてゐるのか把握することができるのである。

NSData の改行

NSData のバイナリデータを Base64 でシリアライズするといふことは、それなりに厖大な長さになることが容易に想像できるかと思ふ。68文字(68バイト)で折疊むのが標準の模樣(どうやらMIMEでの實裝らしい)

コメント

ASCII 形式ほどに編輯頻度は高くない。XML 形式のコメントが當然使へる。

實際のファイル

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Application Version</key><string>8.0.1</string>
	<key>Library Persistent ID</key><string>XXXXXXXXXXXXXXXX</string>
	<key>Major Version</key><integer>1</integer>
	<key>Minor Version</key><integer>1</integer>
	<key>Music Folder</key><string>/Users/XXX/Music/iTunes/iTunes%20Music/</string>
	<key>Playlists</key>
	<array>
	 	<dict>
	 	........
	 	</dict>
	 	<dict>
	 	.
	 	.
	 	</dict>
	</array>
</dict>
</plist>

ASCII の Property List と同じ内容とした。dict、array はこのやうに改行することが多いが、data も68文字を越えて改行するとこのやうになる。

<array>
	<data>
		AQEAAw................
		...
		...
		AAAAAAAAAAAA==
	<data>
<array>

バイナリ形式

一部調査中。「bplist00」で始まるバイナリファイル。パフォーマンス向上の爲に考案された。

追記:opensource.apple で公開されてる CF(CoreFoundation) Projectに CFBinaryPList.c といふファイルを發見。なんでもつと早く Carbon を思ひ出さなかつたんだらう・・・。

// CFBinaryPList.c
/*
HEADER
	magic number ("bplist")
	file format version

OBJECT TABLE
	variable-sized objects

	Object Formats (marker byte followed by additional info in some cases)
	null	0000 0000
	bool	0000 1000			// false
	bool	0000 1001			// true
	fill	0000 1111			// fill byte
	int	0001 nnnn	...		// # of bytes is 2^nnnn, big-endian bytes
	real	0010 nnnn	...		// # of bytes is 2^nnnn, big-endian bytes
	date	0011 0011	...		// 8 byte float follows, big-endian bytes
	data	0100 nnnn	[int]	...	// nnnn is number of bytes unless 1111 then int count follows, followed by bytes
	string	0101 nnnn	[int]	...	// ASCII string, nnnn is # of chars, else 1111 then int count, then bytes
	string	0110 nnnn	[int]	...	// Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte uint16_t
		0111 xxxx			// unused
	uid	1000 nnnn	...		// nnnn+1 is # of bytes
		1001 xxxx			// unused
	array	1010 nnnn	[int]	objref*	// nnnn is count, unless '1111', then int count follows
		1011 xxxx			// unused
	set	1100 nnnn	[int]	objref* // nnnn is count, unless '1111', then int count follows
	dict	1101 nnnn	[int]	keyref* objref*	// nnnn is count, unless '1111', then int count follows
		1110 xxxx			// unused
		1111 xxxx			// unused

OFFSET TABLE
	list of ints, byte size of which is given in trailer
	-- these are the byte offsets into the file
	-- number of these is in the trailer

TRAILER
	byte size of offset ints in offset table
	byte size of object refs in arrays and dicts
	number of offsets in offset table (also is number of objects)
	element # in offset table which is top level object
	offset table offset
*/

解説

書き出すと長くなりさうだし、PropertyList Editor で書き出したファイルと上の註釋とを照らし合はせてほしい。

コメント

そんなものはない。素人に編輯はできない。