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 による解析 > 値検証の制御 | << | >> |