XQueryによる要素抽出と文字列操作
XQueryちょっと好きになってきました。XQueryによる要素抽出と文字列操作を、ちょっとだけ複雑な題材をつかって実際にやってみます。
題材として使用するのは、次のようなスキーマのXMLです。
SimpleRecords要素が繰り返します。
<xsd:element name="SimpleServiceMsg"> <xsd:complexType> <xsd:sequence> <xsd:element name="SimpleRecords" minOccurs="1" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="input0" type="xsd:string"/> <xsd:element name="input1" type="xsd:string"/> <xsd:element name="input2" type="xsd:string"/> <xsd:element name="input3" type="xsd:string"/> <xsd:element name="input4" type="xsd:string"/> <xsd:element name="input5" type="xsd:string"/> <xsd:element name="input6" type="xsd:dateTime"/> <xsd:element name="input7" type="xsd:boolean"/> <xsd:element name="input8" type="xsd:decimal"/> <xsd:element name="input9" type="xsd:integer"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element>
変換要件1
- XQueryで、input0要素の値の文字長が9桁であるSimpleRecords要素を抽出。
- このときinput0要素の値の先頭を0埋めして10桁にする。
文字長が9桁でないものは、スキップする。
XQuery回答例
文字長が9桁のものだけを抽出するには、forとwhereを組み合わせます。文字長を求めるのはfn:string-length関数を使います。
for $SimpleRecords in $simpleServiceMsg1/SimpleRecords where fn:string-length($SimpleRecords/ns2:input0) = 9
文字列連結はfn:concat関数を使います。XQueryの関数を調べるにはW3CのRecommendationが便利です。
http://www.w3.org/TR/xpath-functions/
let $result := fn:concat("0", $SimpleRecords/ns2:input0/text()) return $result[1]
全体としては、次のような感じ。全体のメッセージの中のinput0要素の値だけ、文字列操作が必要になるので、SimpleRecords要素を作るところと、input0要素を作るところが入れ子になって、メッセージを作っています。
<SimpleServiceMsg> { for $SimpleRecords in $simpleServiceMsg1/SimpleRecords where fn:string-length($SimpleRecords/ns2:input0) = 9 return <SimpleRecords> <input0> { let $result := fn:concat("0", $SimpleRecords/ns2:input0/text()) return $result[1] }</input0> <input1>{ data($SimpleRecords/input1) }</input1> <input2>{ data($SimpleRecords/input2) }</input2> <input3>{ data($SimpleRecords/input3) }</input3> <input4>{ data($SimpleRecords/input4) }</input4> <input5>{ data($SimpleRecords/input5) }</input5> <input6>{ data($SimpleRecords/input6) }</input6> <input7>{ data($SimpleRecords/input7) }</input7> <input8>{ data($SimpleRecords/input8) }</input8> <input9>{ data($SimpleRecords/input9) }</input9> </SimpleRecords> } </SimpleServiceMsg>
こういうのが10分くらいですらすら書けるようになるといいな。