| MAP | SASAX ドキュメント > チュートリアル > SASAX による解析 > 値検証の制御 | << | >> |
本節では、
SASAX の ValueElement(およびその派生クラス群)
の値検証処理を制御する方法について説明します。
本節における話題は:
注意: 本節で説明する機能は、SASAX 1.5 以降で利用可能です。
xsi:nil に対応した解析XML Schema 仕様によれば、
(1) XML Schema において nillable="true" が明示され、
(2) XML 文書において xsi:nil="true" が明示された場合、
そのような要素は、XML 文書において空要素でなければいけません。
XML Schema における nillable 属性記述に相当するものとして、
ValueElement は
setNillable(boolean) を提供します。
IntElement element = new IntElement(parent, null, "int");
element.setNillable(true);
この操作により、
「空テキスト」は「int」の制約を満たしませんが、
上記の "element" は
<int xsi:nil="true"/>
を受理できるようになります。
備考: 正当な XML 文書だけを受理するのであれば、 ここで説明する機能は必要ありません。
多くの開発現場においては 〜 少なくとも私の場合は 〜、 仮に「生成側」と「消費側」とで合意した XML スキーマでは許容されていないような文書であっても、 適切な箇所のみに対して処理を継続するために、 文書中の不正な箇所の無視(ないしはそれらの検出)の機能が必要とされます。
前述のように
"setNillable(true)" を用いることで、
空テキストを受理可能な ValueElement を得ることが出来ます。
しかし、
それでも xsi:nil="true"
属性が付けられた要素だけに空であることが許されます。
受理される文書:
<int xsi:nil="true"/>
受理されない文書:
<int/>
実のところ、 空テキストが受理されるか否かは、 それぞれの型固有の検証に依存します。
例えば、
「空テキスト」は「文字列」ですから、
xsi:nil="true" 属性を持っていない要素であっても
"StringElement" は空テキストを受け付けます。
その一方で、
「空テキスト」は「日時」形式の制約を満たしませんので、
"DateTimeElement"
(および多くの ValueElement 派生クラス)
は空テキストを受け付けません。
そのため ValueElement は、
空テキストの場合に検証処理を省略することを指定する
"setIgnoreEmpty(true)" メソッドを提供しています。
例えば:
IntElement element = new IntElement(parent, null, "int");
element.setIgnoreEmpty(true);
上記コード例の element は
xsi:nil="true" 属性を持っていない
"<int/>" であっても受理します。
備考: 正当な XML 文書だけを受理するのであれば、 ここで説明する機能は必要ありません。
多くの開発現場においては 〜 少なくとも私の場合は 〜、 仮に「生成側」と「消費側」とで合意した XML スキーマでは許容されていないような文書であっても、 適切な箇所のみに対して処理を継続するために、 文書中の不正な箇所の無視(ないしはそれらの検出)の機能が必要とされます。
ValueElement は
"endElement" SAX イベント(= 対応するタグの終了)受理と同時に、
指定されたテキストに対する検証処理を実施します。
しかし、検証の即時性は、不正要素抜きで処理を継続することを妨げます。
例えば:
<entry name="1"> <int>abcd</int> <!-- 不正な "int" --> <date>2006-12-31</date> </entry> <entry name="2"> <int>1234</int> <date>2006/12/31</date> <!-- 不正な "date" --> </entry> <entry name="3"> <int>1234</int> <date>2006-12-31</date> </entry>
「即時検証」は
name="1" エントリの
int 要素の終了の際に
SAXException を浮揚するため、
文書解析の継続が許されません。
そのため、
正当なエントリ(この場合は name="3" のエントリ)を処理し、
それ以外の不正なエントリに関する情報をログ出力したい、
といった状況には「即時検証」はそぐいません。
"setDelayed(true)" を実施することで、
ValueElement が
「要素の終了時に指定されたテキストを検証」することを防止します。
"setDelayed(true)" 実施により、
明示的に "validate()"
を起動するまで検証処理が遅延されます。
そのため、以下のようなコードによって、
不正な "<entry>" を無視(ないし検出)
することが出来ます。
CompositeElement entry =
new CompositeElement(parent, null, "entry");
final
IntElement intElement =
new IntElement(entry, null, "int");
intElement.setDelayed(true);
entry.addMustItem(intElement);
final
DateElement dateElement =
new DateElement(entry, null, "date", ....);
dateElement.setDelayed(true);
entry.addMustItem(dateElement);
entry.addNotification(new Notification(){
public void elementStarted(Element element,
ParseContext context,
Attributes attributes)
{ /* nop */ }
public void elementEnded(Element element,
ParseContext context)
{
try{
Integer intValue =
(Integer)(intElement.validate(context, false));
// 「遅延された」検証の実施
Date dateValue =
(Date)(dateElement.validate(context, false));
// 「遅延された」検証の実施
/* 固有の処理をここで実施 ..... */
}
catch(Exception e){
/* 検証エラーの詳細を記録 */
}
}
});
ちなみに、
"addMustItem()" のかわりに
"addOptionalItem()" を用いることで、
不完全な "<entry>" を無視
(ないしは検出)することも出来ます。
本チュートリアルでは、 クラスは全てクラス名のみで表記されています。 完全な名称は以下の通りです。
| Notation | Full name |
|---|---|
| CompositeElement | jp.ne.dti.lares.foozy.sasax.CompositeElement |
| DateElement | jp.ne.dti.lares.foozy.sasax.DateElement |
| Element | jp.ne.dti.lares.foozy.sasax.Element |
| IntElement | jp.ne.dti.lares.foozy.sasax.IntElement |
| Notification | jp.ne.dti.lares.foozy.sasax.Notification |
| ParseContext | jp.ne.dti.lares.foozy.sasax.ParseContext |
| StringElement | jp.ne.dti.lares.foozy.sasax.StringElement |
| ValueElement | jp.ne.dti.lares.foozy.sasax.ValueElement |
| MAP | SASAX ドキュメント > チュートリアル > SASAX による解析 > 値検証の制御 | << | >> |