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     *   &lt;ROWSET tableName="XX" &gt;
063     *       &lt;EXEC_SQL&gt;                    æœ??ã«è¨˜è¼‰ã—ã¦ã€å?期å?ç?ãƒ??タクリアç­?を実行ã•ã›ã‚‹ã€?
064     *           delete from GEXX where YYYYY
065     *       &lt;/EXEC_SQL&gt;
066     *       &lt;MERGE_SQL&gt;                   ã“ã?SQLæ–?§ UPDATEã—ã¦ã€çµæžœãŒï¼ä»¶ãªã‚‰INSERTを行ã„ã¾ã™ã?
067     *           update GEXX set AA=[AA] , BB=[BB] where CC=[CC]
068     *       &lt;/MERGE_SQL&gt;
069     *       &lt;ROW num="1"&gt;
070     *           &lt;カラ�&gt;値1&lt;/カラ�&gt;
071     *             ?¥?¥?¥
072     *           &lt;カラ�&gt;値n&lt;/カラ�&gt;
073     *       &lt;/ROW&gt;
074     *        ?¥?¥?¥
075     *       &lt;ROW num="n"&gt;
076     *          ?¥?¥?¥
077     *       &lt;/ROW&gt;
078     *       &lt;EXEC_SQL&gt;                    æœ?¾Œã«è¨˜è¼‰ã—ã¦ã€??ç›®ã®è¨­å®?æ•´åˆæ?登録)を行ã†ã€?
079     *           update GEXX set AA='XX' , BB='YY' where CC='ZZ'
080     *       &lt;/EXEC_SQL&gt;
081     *   &lt;ROWSET&gt;
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&gt; ã‚¿ã‚°ã® 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    }