July 2008
July 29, 2008
SWT Browser Widget
HTMLをレンダリングするJavaクライアントアプリを作成する。
JDKをインストールする。
http://java.sun.com/javase/downloads/index.jsp
Eclipse(Eclipse IDE for Java EE Developers)をダウンロードする。
http://www.eclipse.org/downloads/
SWTをダウンロードする。
http://www.eclipse.org/swt/
SWT(zip)をC:\java\swttestに解凍する。
JAVA_HOME\binを環境変数PATHに追加する。
BrowsetTestクラスを作成する。
JDKをインストールする。
http://java.sun.com/javase/downloads/index.jsp
Eclipse(Eclipse IDE for Java EE Developers)をダウンロードする。
http://www.eclipse.org/downloads/
SWTをダウンロードする。
http://www.eclipse.org/swt/
SWT(zip)をC:\java\swttestに解凍する。
JAVA_HOME\binを環境変数PATHに追加する。
C:\Program Files\Java\jdk1.6.0_07\binEclipseに含まれるSWTを展開する。
C:\HOME>cd C:\ECLIPSE_HOME\plugins C:\ECLIPSE_HOME\plugins>jar xvf org.eclipse.swt.win32.win32.x86_x.x.x.vxxxxf.jar展開して出てきた.dllファイルをC:\java\swttestに移動する。
BrowsetTestクラスを作成する。
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.browser.*;
public class BrowserTest
{
public static void main(String args[])
{
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(800, 600);
shell.open();
Browser browser = new Browser(shell, SWT.NONE);
browser.setBounds(shell.getClientArea());
browser.setUrl("http://www.google.com/");
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
コンパイル & 実行
C:\java\swttest>javac -classpath swt.jar;. BrowserTest.java C:\java\swttest>java -classpath swt.jar;. BrowserTest
July 21, 2008
PHP - XML(3)
XMLにおける、複数のネームスペースと複数のスキーマによるバリデーションの考察。
user要素は以下のようなprofile要素(型)を持つとする。
profile.xsdにはprofile型(複合型)、age型(単純型)、prefecture型(単純型)が含まれるため、それらを宣言する。
userにprofile要素を追加する。
user要素は以下のようなprofile要素(型)を持つとする。
<profile> <age>18</age> <prefecture>Tokyo</prefecture> </profile>このprofile型は他でも使えるかもしれない、という場合、profile型を定義するスキーマ"profile.xsd"を作成する。この時、このprofile型はネームスペース"prf"に属することとする。
profile.xsdにはprofile型(複合型)、age型(単純型)、prefecture型(単純型)が含まれるため、それらを宣言する。
<element name="profile" type="prf:PROFILE_CTYPE" /> <element name="age" type="prf:PROFILE_AGE_STYPE" /> <element name="prefecture" type="prf:PROFILE_PREFECTURE_STYPE" />単純型の定義を行う。
<simpleType name="PROFILE_AGE_STYPE">
<restriction base="integer">
<minInclusive value="18" />
<maxInclusive value="120" />
</restriction>
</simpleType>
<simpleType name="PROFILE_PREFECTURE_STYPE">
<restriction base="string" />
</simpleType>
定義した単純型を参照し、profile型を定義する。
<complexType name="PROFILE_CTYPE">
<sequence>
<element ref="prf:age" />
<element ref="prf:prefecture" />
</sequence>
</complexType>
出来上がったprofile.xsdの全体。
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://mydomain/profns"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:prf="http://mydomain/profns">
<element name="profile" type="prf:PROFILE_CTYPE" />
<element name="age" type="prf:PROFILE_AGE_STYPE" />
<element name="prefecture" type="prf:PROFILE_PREFECTURE_STYPE" />
<simpleType name="PROFILE_AGE_STYPE">
<restriction base="integer">
<minInclusive value="18" />
<maxInclusive value="120" />
</restriction>
</simpleType>
<simpleType name="PROFILE_PREFECTURE_STYPE">
<restriction base="string" />
</simpleType>
<complexType name="PROFILE_CTYPE">
<sequence>
<element ref="prf:age" />
<element ref="prf:prefecture" />
</sequence>
</complexType>
</schema>
XMLでuserは以下のように記述される(プロフィールは除外してある)。
<user> <id>1</id> <registeredDate>2008-01-01T10:00:00</registeredDate> </user>userはネームスペース"usr"に属することとした場合、XMLは次のように変更される。
<usr:user> <usr:id>1</usr:id> <usr:registeredDate>2008-01-01T10:00:00</usr:registeredDate> </usr:user>ネームスペース"usr"のスキーマ定義を行う。
<element name="users" type="usr:USERS_CTYPE" />
<element name="user" type="usr:USER_CTYPE" />
<element name="id" type="usr:USER_ID_STYPE" />
<element name="registeredDate" type="usr:USER_REGISTERED_DATE_STYPE" />
<complexType name="USERS_CTYPE">
<sequence>
<element ref="usr:user" minOccurs="1" maxOccurs="unbounded" />
</sequence>
</complexType>
<simpleType name="USER_ID_STYPE">
<restriction base="integer" />
</simpleType>
<simpleType name="USER_REGISTERED_DATE_STYPE">
<restriction base="dateTime" />
</simpleType>
<complexType name="USER_CTYPE">
<sequence>
<element ref="usr:id" />
<element ref="usr:registeredDate" />
</sequence>
</complexType>
次に、userはprofileを持つという定義の実装を行う。profile型は外部(profile.xsd)で定義されているため、それをインポートする。
<import namespace="http://mydomain/profns"
schemaLocation="http://mydomain/xmlSchema/profile.xsd" />
インポートするとprofile型が参照できるようになる。userにprofile要素を追加する。
<complexType name="USER_CTYPE">
<sequence>
...
<element ref="prf:profile" />
</sequence>
</complexType>
出来上がったuser.xsdの全体。
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://mydomain/userns"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:usr="http://mydomain/userns"
xmlns:prf="http://mydomain/profns">
<import namespace="http://mydomain/profns"
schemaLocation="http://mydomain/xmlSchema/profile.xsd" />
<element name="users" type="usr:USERS_CTYPE" />
<element name="user" type="usr:USER_CTYPE" />
<element name="id" type="usr:USER_ID_STYPE" />
<element name="registeredDate" type="usr:USER_REGISTERED_DATE_STYPE" />
<complexType name="USERS_CTYPE">
<sequence>
<element ref="usr:user" minOccurs="1" maxOccurs="unbounded" />
</sequence>
</complexType>
<simpleType name="USER_ID_STYPE">
<restriction base="integer" />
</simpleType>
<simpleType name="USER_REGISTERED_DATE_STYPE">
<restriction base="dateTime" />
</simpleType>
<complexType name="USER_CTYPE">
<sequence>
<element ref="usr:id" />
<element ref="usr:registeredDate" />
<element ref="prf:profile" />
</sequence>
</complexType>
</schema>
これらのスキーマ定義に沿うXMLの例。
<?xml version="1.0" encoding="utf-8"?>
<usr:users xmlns:usr="http://mydomain/userns"
xmlns:prf="http://mydomain/profns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mydomain/xmlSchema/user.xsd">
<usr:user>
<usr:id>1</usr:id>
<usr:registeredDate>2008-01-01T10:00:00</usr:registeredDate>
<prf:profile>
<prf:age>20</prf:age>
<prf:prefecture>Tokyo</prf:prefecture>
</prf:profile>
</usr:user>
<usr:user>
<usr:id>2</usr:id>
<usr:registeredDate>2008-02-02T15:00:00</usr:registeredDate>
<prf:profile>
<prf:age>30</prf:age>
<prf:prefecture>Aichi</prf:prefecture>
</prf:profile>
</usr:user>
</usr:users>
バリデーションのコード例。
$doc = new DOMDocument();
$doc->loadXML(file_get_contents("/path/to/users.xml"));
$xpath = new DOMXPath($doc);
$res = $xpath->evaluate("//@xsi:schemaLocation");
$doc->schemaValidate($res->item(0)->nodeValue);
試しに年齢を200にするとWarningが発生する。スキーマ定義やprofile.xsdのインポートなど、機能していることがわかる。
Warning: DOMDocument::schemaValidate() [function.DOMDocument-schemaValidate]:
Element '{http://mydomain/profns}age': [facet 'maxInclusive'] The value '200' is greater than the maximum value allowed ('120').
in /usr/local/www/data/sabel/app/index/controllers/Index.php on line 17
July 20, 2008
PHP - XML(2)
XMLにおけるスキーマ定義の基本的な検証。
以下のようなXMLの有効性を検証するスキーマ定義を作成する。
以下のようなXMLの有効性を検証するスキーマ定義を作成する。
<?xml version="1.0" encoding="utf-8"?>
<users xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mydomain/xmlSchema/user.xsd">
<user>
<id>1</id>
<registeredDate>2008-01-01T10:00:00</registeredDate>
</user>
<user>
<id>2</id>
<registeredDate>2008-02-02T15:00:00</registeredDate>
</user>
<user>
<id>3</id>
<registeredDate>2008-03-03T20:00:00</registeredDate>
</user>
</users>
まず、複合型となる、ドキュメント要素のusersと子要素のuserを定義する。
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="users" type="DEF_USERS" /> <xsd:element name="user" type="DEF_USER" /> <xsd:complexType name="DEF_USERS"> </xsd:complexType> <xsd:complexType name="DEF_USER"> </xsd:complexType> </xsd:schema>次に、usersにuserが1つ以上含まれることを定義する。x以上はminOccursで、x以下はmaxOccursで指定する。最大値がいくらでも良い場合はunboundedとする。
...
<xsd:complexType name="DEF_USERS">
<xsd:sequence>
<xsd:element ref="user" minOccurs="1" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
...
次に、userが持つ単純型の要素(idやregisteredDate)の定義を行う。typeで、idは数値型、registeredDateは日付時刻型であることを示す。データ型はstring, boolean, floatなど色々ある。こちらを参照。
...
<xsd:complexType name="DEF_USER">
<xsd:sequence>
<xsd:element name="id" type="xsd:int" />
<xsd:element name="registeredDate" type="xsd:dateTime" />
</xsd:sequence>
</xsd:complexType>
...
できあがったスキーマ定義でバリデーションを行う。
$doc = new DOMDocument();
$doc->loadXML(file_get_contents("/path/to/users.xml"));
$xpath = new DOMXPath($doc);
$res = $xpath->evaluate("//@xsi:schemaLocation");
$doc->schemaValidate($res->item(0)->nodeValue);
userのidの値を"abc"に変更するとWarningが発生する。バリデーションが正常に機能していることが分かる。
Warning: DOMDocument::schemaValidate() [function.DOMDocument-schemaValidate]: Element 'id': 'abc' is not a valid value of the atomic type 'xs:int'. in /usr/local/www/data/sabel/app/index/controllers/Index.php on line 16userを0個にした時のエラー。
Warning: DOMDocument::schemaValidate() [function.DOMDocument-schemaValidate]: Element 'users': Missing child element(s). Expected is ( user ). in /usr/local/www/data/sabel/app/index/controllers/Index.php on line 16userがageを持つように変更。しかし、ageはなくても良いものとする。また、値は整数で18〜120とする(18や120という閾値を含まない場合、minExclusiveやmaxExclusiveにする)。この場合、データ型にintegerを指定するだけでは十分なルールでないため、年齢型を作成する。
...
<xsd:simpleType name="DEF_AGE">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="18" />
<xsd:maxInclusive value="120" />
</xsd:restriction>
</xsd:simpleType>
...
userにageの定義を追加する。データ型には作成したDEF_AGEを指定し、必須要素ではないためminOccursで0を指定する。
...
<xsd:complexType name="DEF_USER">
<xsd:sequence>
...
<xsd:element name="age" type="DEF_AGE" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
...
これでuserにageを持たせられるようになった。不正な値、例えば121とすると以下のようなエラーになる。
Warning: DOMDocument::schemaValidate() [function.DOMDocument-schemaValidate]:
Element 'age': [facet 'maxInclusive'] The value '121' is greater than the maximum value allowed ('120').
in /usr/local/www/data/sabel/app/index/controllers/Index.php on line 16
今回作成したスキーマ定義の全体(user.xsd)
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="users" type="DEF_USERS" />
<xsd:element name="user" type="DEF_USER" />
<xsd:complexType name="DEF_USERS">
<xsd:sequence>
<xsd:element ref="user" minOccurs="1" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="DEF_AGE">
<xsd:restriction base="xsd:integer">
<xsd:minExclusive value="18"/>
<xsd:maxInclusive value="120"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="DEF_USER">
<xsd:sequence>
<xsd:element name="id" type="xsd:int" />
<xsd:element name="registeredDate" type="xsd:dateTime" />
<xsd:element name="age" type="DEF_AGE" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
July 19, 2008
PHP - XML
XMLにおけるネームスペースの基本的な検証。
以下のようなXMLがある。
以下のようなXMLがある。
<?xml version="1.0" encoding="utf-8"?>
<books>
<book>
<title>book title1</title>
<author>author name1</author>
</book>
<book>
<title>book title2</title>
<author>author name2</author>
</book>
</books>
タグ名による要素の取得。
$doc = new DOMDocument();
$doc->loadXML(file_get_contents("/path/to/test.xml"));
$books = $doc->documentElement;
$titles = $books->getElementsByTagName("title");
var_dump($titles->length); // int(2)
bookの1つ目と2つ目に、それぞれネームスペースを与える。ネームスペースのURIは単なる名前で、存在するリソースを示さなくても良い。
<?xml version="1.0" encoding="utf-8"?>
<books>
<book1:book xmlns:book1="http://www.example.com/ns1">
<book1:title>book title1</book1:title>
<book1:author>author name1</book1:author>
</book1:book>
<book2:book xmlns:book2="http://www.example.com/ns2">
<book2:title>book title2</book2:title>
<book2:author>author name2</book2:author>
</book2:book>
</books>
ネームスペース名(URI)を指定した、タグ名による要素の取得をする。
$doc = new DOMDocument();
$doc->loadXML(file_get_contents("/path/to/test.xml"));
$books = $doc->documentElement;
$titles = $books->getElementsByTagName("title");
var_dump($titles->length); // int(2)
$titles = $books->getElementsByTagNameNS("http://www.example.com/ns1", "title");
var_dump($titles->length); // int(1)
$titles = $books->getElementsByTagNameNS("http://www.example.com/ns2", "title");
var_dump($titles->length); // int(1)
親要素にネームスペースが与えられ、子要素のネームスペースが省略されている場合は、子要素は親要素のネームスペースに属することになる。この時、プレフィックスは省略できる。これは先程のXML文書と同等のものとなる。
<?xml version="1.0" encoding="utf-8"?>
<books>
<book xmlns="http://www.example.com/ns1">
<title>book title1</title>
<author>author name1</author>
</book>
<book xmlns="http://www.example.com/ns2">
<title>book title2</title>
<author>author name2</author>
</book>
</books>
子要素がさらに別のネームスペースに属する場合、親要素のネームスペースはそれ以上下位に適用されない。
<?xml version="1.0" encoding="utf-8"?>
<books>
<book xmlns="http://www.example.com/ns1">
<title>book title1</title>
<author>author name1</author>
<foo xmlns="http://www.example.com/foo">
<title>foo</title>
</foo>
</book>
</books>
$doc = new DOMDocument();
$doc->loadXML(file_get_contents("/path/to/test.xml"));
$books = $doc->documentElement;
$titles = $books->getElementsByTagName("title");
var_dump($titles->length); // int(2)
$titles = $books->getElementsByTagNameNS("http://www.example.com/ns1", "title");
var_dump($titles->length); // int(1)
July 18, 2008
Sabel Release Announcement
Sabel-1.1.1がリリースされました。
Sabel 1.1.0で発見されたいくつかのバグが修正されています。
(Http-Request)リクエスト後にGET値やPOST値を破棄するように変更, POST値が0個の場合にファイルアップロードできない問題の修正
(Task-Fixture)Windowsにおける絶対パス判定の正規表現の不具合を修正
(Util-String)エンコーディングにUTF-8を使用している際のtrim()メソッドの正規表現の不具合を修正
(JS)Stringクラス使用時の返り値の不具合修正
(JS)String.capitalizeメソッドのバグ修正
ダウンロードはこちらから。
Sabel 1.1.0で発見されたいくつかのバグが修正されています。
(Http-Request)リクエスト後にGET値やPOST値を破棄するように変更, POST値が0個の場合にファイルアップロードできない問題の修正
(Task-Fixture)Windowsにおける絶対パス判定の正規表現の不具合を修正
(Util-String)エンコーディングにUTF-8を使用している際のtrim()メソッドの正規表現の不具合を修正
(JS)Stringクラス使用時の返り値の不具合修正
(JS)String.capitalizeメソッドのバグ修正
ダウンロードはこちらから。
July 14, 2008
Sabel AjaxUploader Sample
Sabel AjaxUploaderのサンプルを用意しました。
こちらで動作の様子を確認できます(100Mまで)。
コードは以下のような感じです。ジェネレータで生成することもできますが、コード量が少ないのでコピペでも楽かと思います。
コントローラ例

こちらで動作の様子を確認できます(100Mまで)。
コードは以下のような感じです。ジェネレータで生成することもできますが、コード量が少ないのでコピペでも楽かと思います。
コントローラ例
<?php
class Index_Controllers_Upload extends Sabel_Controller_Page
{
public function upload()
{
$this->uploadId = md5hash();
}
public function fetchStatus()
{
$status = apc_fetch("upload_" . $this->request->fetchGetValue("uploadId"));
echo json_encode($status);
exit;
}
public function uploaded()
{
echo "uploaded";
exit;
}
}
uploadアクションのテンプレート例(Sabelレンダラ使用)
<script type="text/javascript" src="<?= linkto("js/Sabel.js") ?>"></script>
<script type="text/javascript" src="<?= linkto("js/helpers/AjaxUploader.js") ?>"></script>
<style type="text/css">
@import url("<?= linkto("js/helpers/css/Sabel.css") ?>");
</style>
<div id="progressBar"></div>
<form id="upload_form" enctype="multipart/form-data" action="<?= uri("a: uploaded") ?>" method="post">
<p>
<input type="hidden" name="APC_UPLOAD_PROGRESS" value="<?= $uploadId ?>" />
<input type="file" name="upfile" /><br />
<input type="submit" value="upload" />
</p>
</form>
<script type="text/javascript">
new Sabel.PHP.AjaxUploader("upload_form", "<?= uri("a: fetchStatus") ?>?uploadId=<?= $uploadId ?>", "progressBar");
</script>

July 13, 2008
July 05, 2008
Sabel JS - DatePicker(Sabel.Widget.Calendar)
Sabel 1.1で追加されるSabel.Widget.Calendarのサンプル。
カレンダーで日付を選択し、その選択された日付をインプットに適用するDatePicker.jsを書いてみた。
* 実際にサンプルのように表示するにはSabelに含まれるcssや画像が必要
カレンダーで日付を選択し、その選択された日付をインプットに適用するDatePicker.jsを書いてみた。
DatePicker.js
function datepicker(inputs) {
Sabel.Array.each(inputs, function(input) {
var div = document.createElement("div");
div.style.position = "absolute";
div.style.zIndex = 100;
document.body.appendChild(div);
var self = {
element: Sabel.get(input),
calendar: new Sabel.Widget.Calendar(div, {
callback: function(date) {
self.element.value = date.join("-");
}
}),
render: function() {
self.calendar.render();
}
};
div.style.top = Sabel.Element.getCumulativeTop(self.element) + "px";
div.style.left = Sabel.Element.getCumulativeLeft(self.element) + "px";
self.calendar.WeekDays = ["日", "月", "火", "水", "木", "金", "土"];
self.element.observe("mousedown", self.render);
});
}
インプットのidをdatepicker()関数に渡すだけで使用できる(簡単に使えるようにしているため、任意のタイミングでカレンダーを消すなどの処理はできない)。インプットをクリックすると、そのインプットの位置にカレンダーが表示され、日付をクリックするとインプットに年-月-日が入る。
<script type="text/javascript" src="Sabel.js"></script>
<script type="text/javascript" src="DatePicker.js"></script>
<script type="text/javascript">
new Sabel.Event(window, "load", function() {
datepicker(["inputid1", "inputid2", ...]);
});
</script>
動作の様子はこちら。* 実際にサンプルのように表示するにはSabelに含まれるcssや画像が必要
July 04, 2008
July 03, 2008
grep | sed
以下のような実行ログから失敗したid(\[\d+\]の部分)を抽出する。
結果をfailures.phpに出力。
使用する側のプログラムではissetでチェックしたいのでこの形式に。
in_array()だと遅い。
これに少しはまった。
20080701 15:20:01 SUCCESS: username [10502] 20080701 18:14:41 FAILURE: username [3821] 20080702 08:39:22 SUCCESS: username [9134] 20080702 14:43:52 FAILURE: username [6810] 20080702 21:11:05 SUCCESS: username [8819] 20080703 08:31:34 SUCCESS: username [13266] ...grepで失敗の行を取り出してsedに渡す。
結果をfailures.phpに出力。
grep FAILURE some.log | sed -e 's/^.*\[\([0-9]*\)\]/\1 => 1,/' > failures.phpこんな感じになる。
3821 => 1, 6810 => 1, ...ちょっと付け足してphpの配列にする。
使用する側のプログラムではissetでチェックしたいのでこの形式に。
in_array()だと遅い。
<?php
$failures = array(
3821 => 1,
6810 => 1,
...
);
...
if (!isset($failures[$targetId])) {
// process
}
キャプチャに使う括弧をバックスラッシュでエスケープする必要がある。これに少しはまった。