001 /*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016 package org.opengion.fukurou.xml;
017
018 import org.xml.sax.InputSource;
019 import org.xml.sax.SAXException;
020 import org.xml.sax.Attributes;
021 import org.xml.sax.helpers.DefaultHandler;
022
023 import javax.xml.parsers.SAXParserFactory;
024 import javax.xml.parsers.SAXParser;
025 import javax.xml.parsers.ParserConfigurationException;
026
027 import java.io.Reader;
028 import java.io.IOException;
029 import java.util.Map;
030
031 /**
032 * ã“ã?クラスã¯ã€æ‹¡å¼µã‚ªãƒ©ã‚¯ãƒ« XDKå½¢å¼ã?XMLファイルをå?ç?™ã‚‹ãƒãƒ³ãƒ‰ãƒ©ã§ã™ã?
033 * オラクルXDKå½¢å¼ã?XMLã¨ã¯ã€ä¸‹è¨˜ã?よã†ãª ROWSET をトãƒ??ã¨ã™ã‚‹ ROW ã®
034 * é›?¾ã‚Šã§?‘レコードを表ã—ã?å„ROWã«ã¯ã€ã‚«ãƒ©ãƒ?ã‚’ã‚ーã¨ã™ã‚‹XMLã«ãªã£ã¦ã?¾ã™ã?
035 *
036 * <ROWSET>
037 * <ROW num="1">
038 * <カラ�>値1</カラ�>
039 * ?¥?¥?¥
040 * <カラ�>値n</カラ�>
041 * </ROW>
042 * ?¥?¥?¥
043 * <ROW num="n">
044 * ?¥?¥?¥
045 * </ROW>
046 * <ROWSET>
047 *
048 * ã“ã?å½¢å¼ã§ã‚れã°ã€XDK(Oracle XML Developer's Kit)を利用ã™ã‚Œã°ã€?žå¸¸ã«ç°¡å˜ã«
049 * ãƒ??タベã?スã¨XMLファイルã¨ã®äº¤æ›ãŒå¯èƒ½ã§ã™ã?
050 * <a href="http://otn.oracle.co.jp/software/tech/xml/xdk/index.html" target="_blank" >
051 * XDK(Oracle XML Developer's Kit)</a>
052 *
053 * æ‹¡å¼µXDKå½¢å¼ã¨ã¯ã€ROW 以外ã«ã€SQL処ç?”¨ã‚¿ã‚°(EXEC_SQL)ã‚’æŒã¤ XML ファイルã§ã™ã?
054 * ã¾ãŸã?登録ã™ã‚‹ãƒ??ブル(table)ã‚?ROWSETã‚¿ã‚°ã®å±žæ?æƒ??ã¨ã—ã¦ä»˜ä¸Žã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã?
055 * (大æ–?—å°æ–‡å—ã«æ³¨æ„?
056 * ã“れã¯ã€ã‚ªãƒ©ã‚¯ãƒ«XDKã§å‡¦ç?™ã‚‹å?åˆã?無視ã•れã¾ã™ã?ã§ã€åŒæ§˜ã«æ‰±ã?“ã¨ãŒå?æ¥ã¾ã™ã?
057 * ã“ã?ã€EXEC_SQL ã¯ã€ãれãれã? XMLãƒ??タをデータベã?スã«ç™»éŒ²ã™ã‚‹éš›ã«ã€?
058 * SQL処ç?‚’è‡ªå‹•çš„ã«æµã™ç‚ºã®ã€SQLæ–?‚’記載ã—ã¾ã™ã?
059 * ã“ã?処ç??ã€ã‚¤ãƒ™ãƒ³ãƒˆæ¯Žã«å®Ÿè¡Œã•れる為ã€ãã®é…ç½®é ??é‡è¦ã§ã™ã?
060 * ã“ã?ã‚¿ã‚°ã¯ã€è¤?•°è¨˜è¿°ã™ã‚‹ã“ã¨ã‚‚å?æ¥ã¾ã™ãŒã€BODY部ã«ã¯ã€?¼‘ã¤ã®SQLæ–??ã¿è¨˜è¿°ã—ã¾ã™ã?
061 *
062 * <ROWSET tableName="XX" >
063 * <EXEC_SQL> æœ??ã«è¨˜è¼‰ã—ã¦ã€å?期å?ç?ãƒ??タクリアç?を実行ã•ã›ã‚‹ã€?
064 * delete from GEXX where YYYYY
065 * </EXEC_SQL>
066 * <MERGE_SQL> ã“ã?SQLæ–?§ UPDATEã—ã¦ã€çµæžœãŒï¼ä»¶ãªã‚‰INSERTを行ã„ã¾ã™ã?
067 * update GEXX set AA=[AA] , BB=[BB] where CC=[CC]
068 * </MERGE_SQL>
069 * <ROW num="1">
070 * <カラ�>値1</カラ�>
071 * ?¥?¥?¥
072 * <カラ�>値n</カラ�>
073 * </ROW>
074 * ?¥?¥?¥
075 * <ROW num="n">
076 * ?¥?¥?¥
077 * </ROW>
078 * <EXEC_SQL> æœ?¾Œã«è¨˜è¼‰ã—ã¦ã€??ç›®ã®è¨å®?æ•´åˆæ?登録)を行ã†ã€?
079 * update GEXX set AA='XX' , BB='YY' where CC='ZZ'
080 * </EXEC_SQL>
081 * <ROWSET>
082 *
083 * DefaultHandler クラスを拡張ã—ã¦ã?‚‹ç‚ºã€??常ã®å‡¦ç?¨åŒæ§˜ã«ã€ä½¿ç”¨ã§ãã¾ã™ã?
084 *
085 * InputSource input = new InputSource( reader );
086 * HybsXMLHandler hndler = new HybsXMLHandler();
087 *
088 * SAXParserFactory f = SAXParserFactory.newInstance();
089 * SAXParser parser = f.newSAXParser();
090 * parser.parse( input,hndler );
091 *
092 * ã¾ãŸã?上記ã?処ç?ã®ã‚‚ã?を簡略化ã—ãŸãƒ¡ã‚½ãƒ?ƒ‰:parse( Reader ) ã‚’æŒã£ã¦ã?‚‹ãŸã‚ã€?
093 * 通常ãã?メソãƒ?ƒ‰ã‚’使用ã—ã¾ã™ã?
094 *
095 * HybsXMLHandler ã«ã¯ã€TagElementListener ã‚’ã‚»ãƒ?ƒˆã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã?
096 * ã“れã¯ã€ROW 毎㫠å†?ƒ¨æƒ??ã‚?TagElement オブジェクト化ã—ã?action( TagElement )
097 * ãŒå‘¼ã³å‡ºã•れã¾ã™ã?ã“ã? Listener を介ã—ã¦ã€?¼‘レコードãšã¤å‡¦ç?™ã‚‹ã“ã¨ã?
098 * å¯èƒ½ã§ã™ã?
099 *
100 * @version 4.0
101 * @author Kazuhiko Hasegawa
102 * @since JDK5.0,
103 */
104 public class HybsXMLHandler extends DefaultHandler {
105 /** シスãƒ?ƒ ä¾å˜ã?改行記å·ã‚’ã‚»ãƒ?ƒˆã—ã¾ã™ã? */
106 private static final String CR = System.getProperty("line.separator");
107
108 /** ã“ã?ãƒãƒ³ãƒ‰ãƒ©ã®ãƒˆãƒƒãƒ—ã‚¿ã‚°å? {@value} */
109 public static final String ROWSET = "ROWSET";
110 /** ã“ã?ãƒãƒ³ãƒ‰ãƒ©ã§å–り扱ãˆã‚‹ ROWSETã‚¿ã‚°ã®å±žæ? */
111 public static final String ROWSET_TABLE = "tableName";
112
113 /** ã“ã?ãƒãƒ³ãƒ‰ãƒ©ã§å–り扱ãˆã‚‹ã‚¿ã‚°å? {@value} */
114 public static final String ROW = "ROW";
115 /** ã“ã?ãƒãƒ³ãƒ‰ãƒ©ã§å–り扱ãˆã‚‹ ROWã‚¿ã‚°ã®å±žæ? {@value} */
116 public static final String ROW_NUM = "num";
117 /** ã“ã?ãƒãƒ³ãƒ‰ãƒ©ã§å–り扱ãˆã‚‹ã‚¿ã‚°å? {@value} */
118 public static final String EXEC_SQL = "EXEC_SQL";
119 /** ã“ã?ãƒãƒ³ãƒ‰ãƒ©ã§å–り扱ãˆã‚‹ã‚¿ã‚°å? {@value} */
120 public static final String MERGE_SQL = "MERGE_SQL";
121
122 private Map<String,String> defaultMap = null;
123 private TagElementListener listener = null;
124 private TagElement element = null;
125 private String key = null;
126 private StringBuilder body = null;
127 private boolean bodyIn = false;
128 private int level = 0;
129
130 /**
131 * パã?ス処ç?‚’行ã„ã¾ã™ã?
132 * 通常ã®ãƒ‘ã?ス処ç??簡易メソãƒ?ƒ‰ã«ãªã£ã¦ã?¾ã™ã?
133 *
134 * @param reader パã?ス処ç?”¨ã®Readerオブジェクãƒ?
135 */
136 public void parse( final Reader reader ) {
137 try {
138 SAXParserFactory fact = SAXParserFactory.newInstance();
139 SAXParser parser = fact.newSAXParser();
140
141 InputSource input = new InputSource( reader );
142
143 try {
144 parser.parse( input,this );
145 }
146 catch( SAXException ex ) {
147 if( ! "END".equals( ex.getMessage() ) ) {
148 String errMsg = "XMLパã?スエラー key=" + key + CR
149 + "element=" + element + CR
150 + ex.getMessage() ;
151 if( body != null ) {
152 errMsg = errMsg + CR + body.toString();
153 }
154 throw new RuntimeException( errMsg,ex );
155 }
156 }
157 }
158 catch( ParserConfigurationException ex1 ) {
159 String errMsg = "SAXParser ã®ã‚³ãƒ³ãƒ•ã‚£ã‚°ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãŒæ§‹ç¯‰ã§ãã¾ã›ã‚“ã€?
160 + "key=" + key + CR + ex1.getMessage();
161 throw new RuntimeException( errMsg,ex1 );
162 }
163 catch( SAXException ex2 ) {
164 String errMsg = "SAXParser ãŒæ§‹ç¯‰ã§ãã¾ã›ã‚“ã€?
165 + "key=" + key + CR + ex2.getMessage();
166 throw new RuntimeException( errMsg,ex2 );
167 }
168 catch( IOException ex3 ) {
169 String errMsg = "InputSource ã®èªã¿å–り時ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€?
170 + "key=" + key + CR + ex3.getMessage();
171 throw new RuntimeException( errMsg,ex3 );
172 }
173 }
174
175 /**
176 * å†?ƒ¨ã« TagElementListener を登録ã—ã¾ã™ã?
177 * ã“れã¯ã€?lt;ROW> ã‚¿ã‚°ã® endElement 処ç?¯Žã«å‘¼ã³å‡ºã•れã¾ã™ã?
178 * ã¤ã¾ã‚Šã?行データをå–å¾—é?度ã€TagElement オブジェクトを作æ?ã—ã?
179 * ã“ã? TagElementListener ã® action( TagElement ) メソãƒ?ƒ‰ã‚’呼ã³å‡ºã—ã¾ã™ã?
180 * 何もセãƒ?ƒˆã—ãªã??ã¾ãŸã?ã€null ãŒã‚»ãƒ?ƒˆã•れãŸå?åˆã?ã€ä½•ã‚‚ã—ã¾ã›ã‚“ã€?
181 *
182 * @param listener TagElementListenerオブジェク�
183 */
184 public void setTagElementListener( final TagElementListener listener ) {
185 this.listener = listener;
186 }
187
188 /**
189 * TagElement オブジェクトを作æ?ã™ã‚‹æ™‚ã? åˆæœŸã‚«ãƒ©ãƒ?値をè¨å®šã—ã¾ã™ã?
190 * TagElements オブジェクトã?ã€XMLファイルより作æ?ã™ã‚‹ç‚ºã€??ç›®(カラãƒ?ã‚?
191 * XMLファイルã®ROW属æ?ã«æŒã£ã¦ã?‚‹é ?›®ã¨å€¤ã§ä½œæ?ã•れã¾ã™ã?
192 * ã“ã?カラãƒ?ã‚’ã?外部ã‹ã‚‰åˆæœŸè¨å®šã™ã‚‹ã“ã¨ãŒå¯èƒ½ã§ã™ã?
193 * ãã?å ´åˆã?ã“ã“ã§ç™»éŒ²ã—ãŸã‚«ãƒ©ãƒ??(Mapã«ã€LinkedHashMap を使用ã—ãŸå ´å?
194 * ãŒä¿æŒã•れã¾ã™ã?ã¾ãŸã?ROW属æ?ã«å˜åœ¨ã—ãªã?‚«ãƒ©ãƒ?Œã‚れã°ã€å?ã¨ã¨ã‚‚ã«
195 * åˆæœŸå€¤ã¨ã—ã¦è¨å®šã—ã¦ãŠãã“ã¨ãŒå¯èƒ½ã§ã™ã?
196 * ãªãŠã?ã“ã“ã§ã®Mapã¯ã€ç›´æŽ¥è¨å®šã—ã¦ã?¾ã™ã?ã§ã€ã”注æ„ãã?•ã??
197 *
198 * @param map åˆæœŸã‚«ãƒ©ãƒ??ãƒ??
199 */
200 public void setDefaultMap( final Map<String,String> map ) {
201 defaultMap = map;
202 }
203
204 /**
205 * è¦ç´??ã®æ–?—データã®é€šçŸ¥ã‚’å—ã‘å–りã¾ã™ã?
206 * インタフェース ContentHandler å†?? characters メソãƒ?ƒ‰ã‚’オーãƒã?ライドã—ã¦ã?¾ã™ã?
207 * å?–‡å—データãƒãƒ£ãƒ³ã‚¯ã«å¯¾ã—ã¦ç‰¹æ®Šãªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ (ノã?ドã¾ãŸã?ãƒãƒƒãƒ•ã‚¡ã¸ã®ãƒ??ã‚¿ã®è¿½åŠ??
208 * ãƒ??ã‚¿ã®ãƒ•ァイルã¸ã®å‡ºåŠ›ãªã©) を実行ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã?
209 *
210 * @param buffer æ–?—データé…å?
211 * @param start é…å?å†??é–‹å§‹ä½ç½®
212 * @param length é…å?ã‹ã‚‰èªã¿å–られるæ–?—æ•°
213 * @see org.xml.sax.helpers.DefaultHandler#characters(char[] , int , int )
214 */
215 @Override
216 public void characters( final char[] buffer, final int start, final int length ) throws SAXException {
217 if( ! ROW.equals( key ) && ! ROWSET.equals( key ) && length > 0 ) {
218 body.append( buffer,start,length );
219 bodyIn = true;
220 }
221 }
222
223 /**
224 * è¦ç´??é–‹å§‹é?知をå—ã‘å–りã¾ã™ã?
225 * インタフェース ContentHandler å†?? startElement メソãƒ?ƒ‰ã‚’オーãƒã?ライドã—ã¦ã?¾ã™ã?
226 * パã?サ㯠XML æ–?›¸å†??å?¦ç´??å‰ã§ã“ã?メソãƒ?ƒ‰ã‚’呼ã³å‡ºã—ã¾ã™ã?
227 * å?startElement イベントã«ã¯å¯¾å¿œã™ã‚?endElement イベントãŒã‚りã¾ã™ã?
228 * ã“れã¯ã€è¦ç´?Œç©ºã§ã‚ã‚‹å ´åˆã‚‚変ã‚りã¾ã›ã‚“。対応ã™ã‚?endElement イベントã?å‰ã«ã€?
229 * è¦ç´??コンãƒ?ƒ³ãƒ??部ãŒé?番ã«å ±å‘Šã•れã¾ã™ã?
230 * ã“ã“ã§ã¯ã€ã‚¿ã‚°ãŒãƒ¬ãƒ™ãƒ«?“以上ã?å ´åˆã?ã€ä¸Šä½ã‚¿ã‚°ã®å†?®¹ã¨ã—ã¦å–り扱ã?¾ã™ã?よã£ã¦ã€?
231 * ã‚¿ã‚°ã«åå‰ç©ºé–“ãŒå®šç¾©ã•れã¦ã?‚‹å ´åˆã?ãã?属æ?ã¯å‰Šé™¤ã—ã¾ã™ã?
232 *
233 * @param namespace åå‰ç©ºé–??µ?²?©
234 * @param localName å‰ç½®ä¿®é£¾åã‚’å«ã¾ãªã?ƒãƒ¼ã‚«ãƒ«åã?åå‰ç©ºé–“å?ç?Œè¡Œã‚れãªã??åˆã?空æ–?—å?
235 * @param qname å‰ç½®ä¿®é£¾åã‚’æŒã¤ä¿®é£¾åã?修飾åを使用ã§ããªã??åˆã?空æ–?—å?
236 * @param attributes è¦ç´?«ä»˜åŠ ã•れãŸå±žæ?。属æ?ãŒå˜åœ¨ã—ãªã??åˆã?空㮠Attributesオブジェクãƒ?
237 * @see org.xml.sax.helpers.DefaultHandler#startElement(String , String , String , Attributes )
238 */
239 @Override
240 public void startElement(final String namespace, final String localName,
241 final String qname, final Attributes attributes) throws SAXException {
242 if( ROWSET.equals( qname ) ) {
243 if( listener != null ) {
244 element = new TagElement( ROWSET,defaultMap );
245 element.put( ROWSET_TABLE,attributes.getValue( ROWSET_TABLE ) );
246 listener.actionInit( element );
247 }
248 element = null;
249 }
250 else if( ROW.equals( qname ) ) {
251 element = new TagElement( ROW,defaultMap );
252 String num = attributes.getValue( ROW_NUM );
253 element.setRowNo( num );
254 }
255 else if( EXEC_SQL.equals( qname ) ) {
256 element = new TagElement( EXEC_SQL );
257 }
258 else if( MERGE_SQL.equals( qname ) ) {
259 element = new TagElement( MERGE_SQL );
260 }
261
262 if( level <= 2 ) {
263 key = qname;
264 body = new StringBuilder();
265 }
266 else {
267 // レベル??以上ã?ã‚¿ã‚°ã¯ä¸Šä½ã‚¿ã‚°ã®å†?®¹ã¨ã—ã¦æ‰±ã?¾ã™ã?
268 body.append( "<" ).append( qname );
269 int len = attributes.getLength();
270 for( int i=0; i<len; i++ ) {
271 // åå‰ç©ºé–“ã?宣è¨??ã€å‰Šé™¤ã—ã¦ãŠãã¾ã™ã?ã‚ãã¾ã§ãƒ??ã‚¿ã¨ã—ã¦å–り扱ã?‚ºã§ã™ã?
272 String attr = attributes.getQName(i);
273 if( ! attr.startsWith( "xmlns:" ) ) {
274 body.append( " " );
275 body.append( attr ).append( "=\"" );
276 body.append( attributes.getValue(i) ).append( "\"" );
277 }
278 }
279 body.append( ">" );
280 }
281
282 bodyIn = false; // 入れå状ã®ã‚¿ã‚°ã®BODYéƒ¨ã®æœ‰ç„¡
283 level ++ ;
284 }
285
286 /**
287 * è¦ç´??終äº??知をå—ã‘å–りã¾ã™ã?
288 * インタフェース ContentHandler å†?? endElement メソãƒ?ƒ‰ã‚’オーãƒã?ライドã—ã¦ã?¾ã™ã?
289 * SAX パã?サã¯ã€XML æ–?›¸å†??å?¦ç´??終ã‚りã«ã“ã?メソãƒ?ƒ‰ã‚’呼ã³å‡ºã—ã¾ã™ã?
290 * å?endElement イベントã«ã¯å¯¾å¿œã™ã‚?startElement イベントãŒã‚りã¾ã™ã?
291 * ã“れã¯ã€è¦ç´?Œç©ºã§ã‚ã‚‹å ´åˆã‚‚変ã‚りã¾ã›ã‚“ã€?
292 *
293 * @param namespace åå‰ç©ºé–?URI
294 * @param localName å‰ç½®ä¿®é£¾åã‚’å«ã¾ãªã?ƒãƒ¼ã‚«ãƒ«åã?åå‰ç©ºé–“å?ç?Œè¡Œã‚れãªã??åˆã?空æ–?—å?
295 * @param qname å‰ç½®ä¿®é£¾åã‚’æŒã¤ XML 1.0 修飾åã?修飾åを使用ã§ããªã??åˆã?空æ–?—å?
296 * @see org.xml.sax.helpers.DefaultHandler#endElement(String , String , String )
297 */
298 @Override
299 public void endElement(final String namespace, final String localName, final String qname) throws SAXException {
300 level -- ;
301 if( ROW.equals( qname ) ) {
302 if( listener != null ) {
303 listener.actionRow( element );
304 }
305 element = null;
306 }
307 else if( EXEC_SQL.equals( qname ) ) {
308 element.setBody( body.toString().trim() );
309 if( listener != null ) {
310 listener.actionExecSQL( element );
311 }
312 element = null;
313 }
314 else if( MERGE_SQL.equals( qname ) ) {
315 element.setBody( body.toString().trim() );
316 if( listener != null ) {
317 listener.actionMergeSQL( element );
318 }
319 element = null;
320 }
321 else if( level <= 2 ) {
322 if( element != null ) {
323 element.put( key , body.toString().trim() );
324 }
325 }
326 else {
327 if( bodyIn ) {
328 body.append( "</" ).append( qname ).append( ">" );
329 }
330 else {
331 body.insert( body.length()-1, " /" ); // ã‚¿ã‚°ã®æœ?¾Œã‚’ " />" ã¨ã™ã‚‹ã€?
332 }
333 }
334 }
335 }