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.hayabusa.report2;
017    
018    import java.util.ArrayList;
019    import java.util.List;
020    
021    import org.opengion.hayabusa.common.HybsSystemException;
022    
023    /**
024     * Calc帳票シスãƒ?ƒ でタグのパã?スを行うためのクラスですã?
025     *
026     * 主に開始タグ、終äº?‚¿グを指定したパースのループå?ç�?‚’行うための機è?を提供しますã?
027     * 具体的には、{@link #doParse(String, String, String)}により、パースæ–?­—å?ã€?–‹始タグ、終äº?‚¿グã‚?
028     * æŒ?®šし、パースを行いますã?
029     * パã?ス後ã?æ–?­—å?は、{@link #doParse(String, String, String)}の戻りå?になりますã?
030     *
031     * パã?ス実行中に、発見された開始タグから終äº?‚¿グまでの間ã?æ–?­—å?の処ç�??、{@link #exec(String, StringBuilder, int)}ã‚?
032     * オーバã?ライドすることにより定義しますã?
033     *
034     * またã?こã?クラスでは、パースにå¿?¦�なå�?¨®ユーãƒ?‚£リãƒ?‚£メソãƒ?ƒ‰につã�?�¦も同様に定義されてã�?�¾すã?
035     *
036     * @og.group 帳票シスãƒ?ƒ 
037     *
038     * @version  4.0
039     * @author   Hiroki.Nakamura
040     * @since    JDK1.6
041     */
042    class TagParser {
043    
044            private int preOffset = 0;
045            private int curOffset = 0;
046    
047            /**
048             * パã?ス処ç�?‚’行いますã?
049             *
050             * パã?ス中に取り出された開始タグから終äº?‚¿グまでのæ–?­—å?の処ç�??ã€?
051             * {@link #exec(String, StringBuilder, int)}で定義しますã?
052             *
053             * またã?isAddTagをtrueにした場合ã?{@link #exec(String, StringBuilder, int)}に渡されã‚?
054             * æ–?­—å?にã€?–‹始タグ、終äº?‚¿グが含まれますã?
055             * é€?�«falseにした場合ã?ã€?–‹始タグ、終äº?‚¿グを除きã?{@link #exec(String, StringBuilder, int)}に渡されますã?
056             *
057             * @og.rev 5.2.2.0 (2010/11/01) 読み飛ã?しをした場合にã€?–‹始タグが書き込まれなã�?ƒ�グを修正
058             *
059             * @param content パã?ス対象æ–?­—å?
060             * @param startTag 開始タグ
061             * @param endTag 終äº?‚¿グ
062             * @param isAddTag 開始タグ・終äº?‚¿グを含ã‚?�‹
063             *
064             * @return パã?ス後ã?æ–?­—å?
065             * @see #exec(String, StringBuilder, int)
066             */
067            public String doParse( final String content, final String startTag, final String endTag, final boolean isAddTag ) {
068                    StringBuilder buf = new StringBuilder();
069                    String errMsg = null;
070    
071                    while( ( preOffset = content.indexOf( startTag, Math.max( preOffset, curOffset ) ) ) >= 0 ) {
072                            buf.append( content.substring( curOffset, preOffset ) );
073                            curOffset = content.indexOf( endTag, preOffset + startTag.length() );
074    
075                            if( checkIgnore( preOffset, curOffset ) ) {
076                                    if( curOffset < 0 ){
077                                            errMsg = "[ERROR]PARSE:開始タグを終äº?‚¿グの整合æ?が不正ですã?[開始タグ=" + startTag + ":終äº?‚¿グ=" + endTag + "]";
078                                            throw new HybsSystemException( errMsg );
079                                    }
080                                    preOffset += startTag.length();
081                                    curOffset += endTag.length();
082    
083                                    String str = null;
084                                    if( isAddTag ) {
085                                            str = content.substring( preOffset - startTag.length(), curOffset );
086                                    }
087                                    else {
088                                            str = content.substring( preOffset, curOffset - endTag.length() );
089                                    }
090    
091                                    exec( str, buf, curOffset );
092                            }
093                            else {
094                                    // 5.2.2.0 (2010/11/01) 開始タグが書き込まれなã�?ƒ�グを修正
095                                    buf.append( startTag );
096                                    preOffset += startTag.length();
097                                    curOffset = preOffset;
098                            }
099                    }
100                    buf.append( content.substring( curOffset, content.length() ) );
101    
102                    return buf.toString();
103            }
104    
105            /**
106             * パã?ス処ç�?‚’行いますã?
107             *
108             * 詳細は、{@link #doParse(String, String, String, boolean)}のJavadocを参照して下さã�??
109             *
110             * @param content パã?ス対象æ–?­—å?
111             * @param startTag 開始タグ
112             * @param endTag 終äº?‚¿グ
113             *
114             * @return パã?ス後ã?æ–?­—å?
115             * @see #doParse(String, String, String, boolean)
116             */
117            public String doParse( final String content, final String startTag, final String endTag ) {
118                    return doParse( content, startTag, endTag, true );
119            }
120    
121            /**
122             * 開始タグから終äº?‚¿グまでのæ–?­—å?の処ç�?‚’定義しますã?
123             *
124             * こã?実è£?�§は、何も処ç�?‚’行いませんã€?åˆ?‚Š出したæ–?­—å?はアペンドされません)
125             * サブクラスでオーバã?ライドして実際の処ç�?‚’実è£?�—て下さã�??
126             *
127             * @param str 開始タグから終äº?‚¿グまでのæ–?­—å?(開始タグ・終äº?‚¿グを含ã‚?
128             * @param buf 出力を行うæ–?­—å?バッファ
129             * @param offset 終äº?‚¿グのオフセãƒ?ƒˆ
130             */
131            protected void exec( final String str, final StringBuilder buf, final int offset ) {
132                    // Document empty method 対ç­?
133            }
134    
135            /**
136             * 開始タグから終äº?‚¿グまでのæ–?­—å?の処ç�?‚’実行するかどã�?�‹を定義しますã?
137             *
138             * falseが返された場合ã?何も処ç�?�•れず({@link #exec(String, StringBuilder, int)}が実行されなã�?ã€?
139             * å…??æ–?­—å?がそのまま出力されますã?
140             *
141             * @param strOffset 開始タグのオフセãƒ?ƒˆ
142             * @param endOffset 終äº?‚¿グのオフセãƒ?ƒˆ
143             *
144             * @return 処ç�?‚’行うかどã�?�‹(true:処ç�?‚’行う false:処ç�?‚’行わなã�?
145             */
146            protected boolean checkIgnore( final int strOffset, final int endOffset ) {
147                    return true;
148            }
149    
150            /**
151             * パã?ス実行中のoffset値を外部からセãƒ?ƒˆしますã?
152             *
153             * こã?メソãƒ?ƒ‰は、{@link #exec(String, StringBuilder, int)}で、å?ç�?µ�果により、offset値ã‚?
154             * 進めておくå¿?¦�がある場合に利用されますã?(つまりé?常は利用するå¿?¦�ã?ありません)
155             *
156             * @param offset オフセãƒ?ƒˆ
157             * @see #exec(String, StringBuilder, int)
158             */
159            public void setOffset( final int offset ) {
160                    curOffset = offset;
161            }
162    
163            /**
164             * 引数のæ–?­—å?を指定された開始タグ、終äº?‚¿グで解析し配å?として返す、ユーãƒ?‚£リãƒ?‚£メソãƒ?ƒ‰ですã?
165             *
166             * 開始タグより前ã?æ–?­—å?は0番目に、終äº?‚¿グより後ã?æ–?­—å?は1番目に格納されますã?
167             * 2番目以降にã€?–‹始タグ、終äº?‚¿グの部åˆ?�Œ格納されますã?
168             *
169             * @param str           解析する文字å?
170             * @param startTag      開始タグ
171             * @param endTag        終äº?‚¿グ
172             *
173             * @return 解析結果の配å?
174             */
175            public static String[] tag2Array( final String str, final String startTag, final String endTag ) {
176                    String header = null;
177                    String footer = null;
178                    List<String> body = new ArrayList<String>();
179    
180                    int preOffset = -1;
181                    int curOffset = 0;
182    
183                    while( true ) {
184                            curOffset = str.indexOf( startTag, preOffset + 1 );
185                            if( curOffset < 0 ) {
186                                    curOffset = str.lastIndexOf( endTag ) + endTag.length();
187                                    body.add( str.substring( preOffset, curOffset ) );
188    
189                                    footer = str.substring( curOffset );
190                                    break;
191                            }
192                            else if( preOffset == -1 ) {
193                                    header = str.substring( 0, curOffset );
194                            }
195                            else {
196                                    body.add( str.substring( preOffset, curOffset ) );
197                            }
198                            preOffset = curOffset;
199                    }
200    
201                    String[] arr = new String[body.size()+2];
202                    arr[0] = header;
203                    arr[1] = footer;
204                    for( int i=0; i<body.size(); i++ ) {
205                            arr[i+2] = body.get(i);
206                    }
207    
208                    return arr;
209            }
210    
211            /**
212             * 引数のæ–?­—å?の開始文字と終äº?–‡字ã?間ã?æ–?­—å?を取りå?すã?ユーãƒ?‚£リãƒ?‚£メソãƒ?ƒ‰ですã?
213             * ※返されるæ–?­—å?にã€?–‹始文字ã?終äº?–‡字ã?含まれませんã€?
214             *
215             * @param str   解析する文字å?
216             * @param start 開始文å­?
217             * @param end   終äº?–‡å­?
218             *
219             * @return 解析結果のæ–?­?
220             */
221            public static String getValueFromTag( final String str, final String start, final String end ) {
222                    int startOffset = str.indexOf( start );
223    //              int startOffset = str.indexOf( start ) + start.length();
224                    // 4.2.4.0 (2008/06/02) 存在しなã�??合ã?nullで返す
225                    if( startOffset == -1 ) {
226                            return null;
227                    }
228                    startOffset += start.length();
229    
230                    int endOffset = str.indexOf( end, startOffset );
231                    String value = str.substring( startOffset, endOffset );
232    
233                    return value;
234            }
235    
236            /**
237             * 引数のキーから不要なキーを取り除くã?ユーãƒ?‚£リãƒ?‚£メソãƒ?ƒ‰ですã?
238             *
239             * @og.rev 5.1.8.0 (2010/07/01) spanタグを削除
240             *
241             * @param key   オリジナルのキー
242             * @param sb    キーの外に含まれるaタグを削除するための、バãƒ?ƒ•ァ
243             *
244             * @return 削除後ã?キー
245             */
246            public static String checkKey( final String key, final StringBuilder sb ) {
247                    if( key.indexOf( '<' ) < 0 && key.indexOf( '>' ) < 0 ) { return key; }
248    
249                    StringBuilder rtn = new StringBuilder( key );
250                    String tagEnd = ">";
251                    int rtnOffset = -1;
252    
253                    // <text:a ...>{@XXX</text:a>の不要タグを削除
254                    String delTagStart1 = "<text:a ";
255                    String delTagEnd1 = "</text:a>";
256                    while( ( rtnOffset = rtn.lastIndexOf( delTagEnd1 ) ) >= 0 ) {
257                            boolean isDel = false;
258                            // キー自身に含まれるaタグを削除
259                            int startOffset = rtn.lastIndexOf( delTagStart1, rtnOffset );
260                            if( startOffset >= 0 ) {
261                                    int endOffset = rtn.indexOf( tagEnd, startOffset );
262                                    if( endOffset >= 0 ) {
263                                            rtn.delete( rtnOffset, rtnOffset + delTagEnd1.length() );
264                                            rtn.delete( startOffset, endOffset + tagEnd.length() );
265                                            isDel = true;
266                                    }
267                            }
268                            else {
269                                    // キーの外に含まれるaタグを削除
270                                    startOffset = sb.lastIndexOf( delTagStart1 );
271                                    if( startOffset >= 0 ) {
272                                            int endOffset = sb.indexOf( tagEnd, startOffset );
273                                            if( endOffset >= 0 ) {
274                                                    rtn.delete( rtnOffset, rtnOffset + delTagEnd1.length() );
275                                                    sb.delete( startOffset, endOffset + tagEnd.length() );
276                                                    isDel = true;
277                                            }
278                                    }
279                            }
280                            if( !isDel ) { break; }
281                    }
282    
283                    // 5.1.8.0 (2010/07/01) spanタグを削除
284                    String delTagStart2 = "<text:span ";
285                    String delTagEnd2 = "</text:span>";
286                    while( ( rtnOffset = rtn.lastIndexOf( delTagEnd2 ) ) >= 0 ) {
287                            boolean isDel = false;
288                            // キー自身に含まれるspanタグを削除
289                            int startOffset = rtn.lastIndexOf( delTagStart2, rtnOffset );
290                            if( startOffset >= 0 ) {
291                                    int endOffset = rtn.indexOf( tagEnd, startOffset );
292                                    if( endOffset >= 0 ) {
293                                            rtn.delete( rtnOffset, rtnOffset + delTagEnd2.length() );
294                                            rtn.delete( startOffset, endOffset + tagEnd.length() );
295                                            isDel = true;
296                                    }
297                            }
298                            else {
299                                    // キーの外に含まれるspanタグを削除
300                                    startOffset = sb.lastIndexOf( delTagStart2 );
301                                    if( startOffset >= 0 ) {
302                                            int endOffset = sb.indexOf( tagEnd, startOffset );
303                                            if( endOffset >= 0 ) {
304                                                    rtn.delete( rtnOffset, rtnOffset + delTagEnd2.length() );
305                                                    sb.delete( startOffset, endOffset + tagEnd.length() );
306                                                    isDel = true;
307                                            }
308                                    }
309                            }
310                            if( !isDel ) { break; }
311                    }
312    
313                    return rtn.toString();
314            }
315    }
316