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.report;
017    
018    import org.opengion.hayabusa.common.HybsSystem;
019    import org.opengion.hayabusa.common.HybsSystemException;
020    import org.opengion.fukurou.util.LogWriter;
021    
022    import org.opengion.fukurou.util.QrcodeImage;
023    import org.opengion.fukurou.util.ReplaceString;
024    
025    import java.io.IOException;
026    import java.util.Map ;
027    import java.util.HashMap ;
028    import java.util.regex.Pattern;
029    import java.util.regex.Matcher ;
030    
031    /**
032     * DBTableReport インターフェース を実è£?�—たHTMLをパースするクラスですã?
033     * AbstractDBTableReport を継承してã�?�¾すã?で?ŒwriteReport() のみオーバã?ライドして??
034     * 固定長æ–?­—ファイルの出力機è?を実現してã�?�¾すã?
035     *
036     * @og.group 帳票シスãƒ?ƒ 
037     *
038     * @version  4.0
039     * @author   Kazuhiko Hasegawa
040     * @since    JDK5.0,
041     */
042    public class DBTableReport_HTML extends AbstractDBTableReport {
043            private static final String TR_IN        = "<tr" ;
044            private static final String TR_OUT       = "</tr>" ;
045            private static final String TD_OUT       = "</td>" ;                      // 3.5.5.9 (2004/06/07)
046            private static final String PAGE_BREAK   = "page-break" ;
047            private static final String PAGE_END_CUT = "PAGE_END_CUT" ;             // 3.6.0.0 (2004/09/17)
048            private static final String END_TAG      = "</table></body></html>";
049            private static final String CUT_TAG1     = "<span";
050            private static final String CUT_TAG2     = "</span>";
051            private static final String SPACE_ST     = "<span style=\"mso-spacerun: yes\">";  // 3.6.0.0 (2004/09/17)
052            private static final String SPACE        = "&nbsp;";                                                                // 3.6.0.0 (2004/09/17)
053            private static final String SPACE_ED     = " </span>";                                                    // 3.6.0.0 (2004/09/17)
054            private static final String FRAMESET     = "Excel Workbook Frameset" ;
055    
056            private static final String CR         = System.getProperty("line.separator");
057    
058            // <td xxx="yyy">zzzz</td> 形式とマッチしã€?zzzz< 部åˆ?‚’前方参ç?しますã?
059            private static final Pattern PTN1 = Pattern.compile("<td[^>]*(>.*?<)/td>");
060            // >aaaa<span bb="cc">dddd</span>eeee< 形式に?’文字以上ã?スペã?スを含ã‚?ƒ‡ータと
061            // マッチし、aaaa,dddd,eeee を前方参ç?しますã?
062            private static final Pattern PTN2 = Pattern.compile("[^>]*>([^<]*?  ++[^<]*?)<");
063            // aa   bb    cc    形式とマッチし、各連続スペã?ス部åˆ?‚’前方参ç?しますã?
064            private static final Pattern PTN3 = Pattern.compile("(  +)");
065    
066            private boolean  fileEnd        = false;                // ファイルの読み取り制御
067    
068            // 3.6.1.0 (2005/01/05) QRコーãƒ??’次å…?ƒ�ーコーãƒ?用の出力ファイル管ç�?
069            private Map<String,String> qrFileMap = null;
070            // <v:shape ?¥?¥?¥ alt="{@QRCODE.XXXX}" ?¥?¥?¥>
071            //   <v:imagedata src="yyy" ?¥?¥?¥>?¥?¥?¥</v:shape>形式とマッチしã€?
072            // xxx 部åˆ?�¨、yyy 部åˆ?‚’前方参ç?しますã?
073            private static final Pattern IMGPTN1 = Pattern.compile("<v:shape [^>]*alt=\"\\{@QRCODE.([^\\}]*)\\}\"[^>]*>[^<]*<v:imagedata [^>]*src=\"([^\"]*)\"[^>]*>");
074            // <img ?¥?¥?¥ src="yyy" ?¥?¥?¥ alt="{@QRCODE.XXXX}" ?¥?¥?¥ > 形式とマッチしã€?
075            // yyy 部åˆ?�¨、xxx 部åˆ?‚’前方参ç?しますã?
076            private static final Pattern IMGPTN2 = Pattern.compile("<img [^>]*src=\"([^\"]*)\"[^>]*alt=\"\\{@QRCODE.([^\\}]*)\\}\"[^>]*>");
077    
078            // 4.0.0 (2007/06/08) pageEndCut = true  時ã? LINE_COPY 機è?の実è£?
079            private static final String LINE_COPY = "LINE_COPY" ;           // 4.0.0 (2007/06/08)
080            private String lineCopy = null;
081    
082            /**
083             * 入力文字å? を読み取って、å?力しますã?
084             * tr タグを目印にã€?¼‘è¡?trタグé–?ずつ取り出しますã?
085             * 読み取りを終äº?�™るå?合ã?、null を返しますã?
086             * å�?‚µブクラスで実è£?�—てくださいã€?
087             *
088             * @og.rev 3.0.0.1 (2003/02/14) ä¸?º¦もValueセãƒ?ƒˆしてã�?�ªã�??に次ペã?ジ要求があったå?合ã?、フォーマットがおかしい
089             * @og.rev 3.6.0.0 (2004/09/24) フォーマットエラーの判å®?formatErr)をã?親クラスに移動しますã?
090             *
091             * @return      出力文字å?
092             */
093            @Override
094            protected String readLine() {
095                    if( fileEnd ) { return null; }
096    
097                    // pageEndCut 時に、データがオーバã?してã�?�ªã�?–“のみ、lineCopy があれã?返すã€?
098                    if( pageEndCut && !rowOver && lineCopy != null ) {
099                            lineCopyCnt ++ ;        // 雛形は、_0 のみが毎回返される為の、加ç®?
100                            return lineCopy ;
101                    }
102    
103                    final StringBuilder buf ;
104                    try {
105                            String line = reader.readLine();
106                            if( line == null ) {
107                                    if( rowOver ) {
108                                            return null;
109                                    }
110                                    else {
111                                            initReader();
112                                            initWriter();
113                                            line = reader.readLine();
114                                            if( line == null ) { return null; }
115                                    }
116                            }
117                            if( line.indexOf( FRAMESET )  >= 0 ) {
118                                    String errMsg = "HTML ファイルエラー :" + line + HybsSystem.CR
119                                                                    + "Excelファイル形式がフレーãƒ?�«なってã�?�¾すã?(è¤?•°シートには未対å¿?" ;
120                                    throw new HybsSystemException( errMsg );
121                            }
122                            if( line.indexOf( TR_IN )  >= 0 ) {
123                                    buf = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
124                                    buf.append( line );
125                                    int trLebel = 1;                        // 行を表ã�?<tr> のレベル
126                                    while( trLebel != 0 ) {
127                                            line = reader.readLine();
128                                            // 4.0.0 (2005/08/31) null 参ç?はずし対å¿?
129                                            if( line != null ) {
130                                                    if( line.indexOf( TR_IN  ) >= 0 ) { trLebel++ ; }
131                                                    if( line.indexOf( TR_OUT ) >= 0 ) { trLebel-- ; }
132                                                    buf.append( CR ).append( line );
133                                            }
134                                            else {
135                                                    String errMsg = "HTML ファイルエラー :" + buf.toString() + HybsSystem.CR
136                                                                            + "è¡?TR)の整合æ?が取れる前に、ファイルが終äº?�—ましたã€? ;
137                                                    throw new HybsSystemException( errMsg );
138                                            }
139                                    }
140                            }
141                            else {
142                                    return line;
143                            }
144                    } catch(IOException ex) {
145                            String errMsg = "HTML ファイル 読取時にエラーが発生しましたã€? + reader;
146                            throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並びé ?¤‰更
147                    }
148    
149                    String rtnLine = buf.toString() ;
150    
151                    // lineCopy æƒ??の取得ã?
152                    if( pageEndCut && !rowOver ) {
153                            // LINE_COPY は削除しますã?で、表示上見えるよã�?�«しておいてくださいã€?
154                            int adrs = rtnLine.indexOf( LINE_COPY );
155                            if( adrs >= 0 ) {
156                                    lineCopy = rtnLine.substring( 0,adrs )
157                                                            + rtnLine.substring( adrs + LINE_COPY.length() ) ;
158                                    rtnLine = lineCopy ;
159                            }
160                    }
161    
162                    return rtnLine ;
163            }
164    
165            /**
166             * 入力文字å? を加工して、å?力しますã?
167             * {&#064;XXXX} をテーブルモãƒ?ƒ«より読み取り、å?をセãƒ?ƒˆしますã?
168             * å�?‚µブクラスで実è£?�—てくださいã€?
169             *
170             * @og.rev 3.0.0.1 (2003/02/14) ä¸?º¦もValueセãƒ?ƒˆしてã�?�ªã�??に次ペã?ジ要求があったå?合ã?、フォーマットがおかしい
171             * @og.rev 3.0.0.2 (2003/02/20) {&#064;XXXX}æ–?­—が、EXCELに表示しきれなã�??合に挿入されるタグの削除処ç�??変更ã€?
172             * @og.rev 3.5.0.0 (2003/09/17) {&#064;XXXX}æ–?­—ã?スペã?スをã?&amp;nbsp;と置き換えますã?
173             * @og.rev 3.5.0.0 (2003/09/17) {&#064;XXXX}æ–?­—がアンバランス時にHybsSystemExceptionを発行するã?
174             * @og.rev 3.5.5.9 (2004/06/07) {&#064;XXXX}の連続å?ç�??アドレス計算方法がã€?–“違ってã�?�¾したので修正しますã?
175             * @og.rev 3.6.0.0 (2004/09/17) pageEndCut ã�?true の場合ã?、PAGE_END_CUT æ–?­—å?のある行を削除しますã?
176             * @og.rev 3.6.0.0 (2004/09/24) フォーマットエラーの判å®?formatErr)をã?親クラスに移動しますã?
177             * @og.rev 3.6.1.0 (2005/01/05) QRコーãƒ??’次å…?ƒ�ーコーãƒ?の機è?追åŠ?
178             * @og.rev 3.8.1.2 (2005/12/19) PAGE_END_CUTの判定にdataOver フラグを使用ã€?
179             *
180             * @param       inLine  入力文字å?
181             *
182             * @return      出力文字å?
183             */
184            @Override
185            protected String changeData( final String inLine ) {
186                    // rowOver で、かつ ペã?ジブレークかã?ージエンドカãƒ?ƒˆの場合ã?処ç�?µ‚äº??
187                    if( rowOver && ( inLine.indexOf( PAGE_BREAK ) >= 0 ) ) {
188                            fileEnd = true;
189                            return END_TAG;
190                    }
191    
192                    String chLine = changeHeaderFooterData( inLine ) ;
193    
194                    // 3.6.1.0 (2005/01/05) QRコーãƒ??’次å…?ƒ�ーコーãƒ?の機è?追åŠ?
195                    if( chLine.indexOf( "{@QRCODE." ) >= 0 ) {
196                            chLine = qrcodeReplace( chLine );
197                    }
198    
199                    int st = chLine.indexOf( "{@" );
200                    // 3.8.1.2 (2005/12/19) {@XXXX}の存在しなã�?¡Œも PAGE_END_CUTの判定を行うã€?
201    
202                    StringBuilder buf = new StringBuilder( chLine );
203    
204                    boolean spaceInFlag = false;    // {@XXXX} 変数のãƒ??タにスペã?スを含ã‚?�‹どã�?�‹チェãƒ?‚¯
205                    while( st >= 0 ) {
206                            int end = buf.indexOf( "}",st+2 );
207    
208                            // EXCELに表示しきれなã�?–‡字ã?、CUT_TAG1,CUT_TAG2 が挿入されてしまã�?‚ºã€?
209                            // 削除するå¿?¦�があるã€?
210                            int cutSt1 = buf.indexOf( CUT_TAG1,st+2 );
211                            if( cutSt1 >= 0 && cutSt1 < end ) {
212                                    int cutEnd1 = buf.indexOf( ">",cutSt1 );
213    
214                                    int cutSt2 = buf.indexOf( CUT_TAG2,end );
215                                    if( cutSt2 >= 0 ) {
216                                            buf.delete( cutSt2, cutSt2 + CUT_TAG2.length() );
217                                    }
218                                    buf.delete( cutSt1, cutEnd1+1 );
219                                    // 途中をカãƒ?ƒˆした為、もã�?¸?º¦計算しなおしã€?
220                                    end = buf.indexOf( "}",st+2 );          // 3.5.5.9 (2004/06/07)
221                            }
222    
223                            // 3.5.5.9 (2004/06/07)
224                            // 関数等を使用すると、{@XXXX} æ–?­—å?を直接åŠ?·¥したãƒ??タがå?力されるã€?
225                            // こã?åŠ?·¥されたデータは、HTML 表示に使用されるだけã?ため、削除しますã?
226                            // 削除方法ã?、{@XXX</td> を想定してã�?‚‹為ã€?{@ から </td> の間ですã?
227                            int td_out = buf.indexOf( TD_OUT,st+2 );
228                            if( td_out >= 0 && td_out < end ) {
229                                    buf.delete( st, td_out );
230                                    // {@XXXX} パラメータが消えたã?で、次の計算を行いますã?
231                                    st = buf.indexOf( "{@",st+4 );          // 3.5.5.9 (2004/06/07)
232                                    continue ;
233                            }
234    
235                            // 途中をカãƒ?ƒˆした為、もã�?¸?º¦計算しなおしã€?
236                            // フォーマットがおかしい場合ã?処ç�?
237                            if( end < 0 ) {
238                                    String errMsg = "こã?ãƒ?ƒ³プレートファイルの {@XXXX} がã?フォーマットエラーですã?"
239                                                                    + HybsSystem.CR
240                                                                    + chLine.substring( st ) ;
241                                    throw new HybsSystemException( errMsg );
242                            }
243    
244                            String key = buf.substring( st+2,end );
245    
246                            String val = getValue( key );
247                            if( val.indexOf( "  " ) >= 0 ) { spaceInFlag = true; }
248    
249                            // {@XXXX} ã‚?実際の値と置き換えるã€?
250                            buf.replace( st,end+1,val );
251    
252                            // {@ の 存在チェãƒ?‚¯ã€?
253                            st = buf.indexOf( "{@",st-1 );          // 3.5.5.9 (2004/06/07)
254                    }
255    
256                    // 3.6.0.0 (2004/09/17) pageEndCut ã�?true の場合ã?、PAGE_END_CUT æ–?­—å?のある行を削除しますã?
257                    // ここで判定するã?は、PAGE_END_CUT æ–?­—そのもã?がã?åŠ?·¥されてã�?‚‹可能性があるためã?
258                    String rtn = buf.toString();
259                    if( dataOver && pageEndCut ) {          // 3.8.1.2 (2005/12/19)
260                            String temp = rtn.replaceAll( CUT_TAG1 + "[^>]*>" ,"" );
261                            if( temp.indexOf( PAGE_END_CUT ) >= 0 ) {
262                                    rtn = "" ;
263                            }
264                    }
265                    else {
266                            // 3.6.0.0 (2004/09/17) スペã?ス置き換えã?ã€?td XXX>YYY</td> の YYYのç¯?›²のみとするã€?
267                            if( spaceInFlag ) {
268                                    rtn = spaceReplace( rtn ) ;
269                            }
270                    }
271                    return rtn ;
272            }
273    
274            /**
275             * è¶?‰¹殊å?ç�??
276             * EXCEL の ヘッãƒ??/フッター部åˆ??、\{\&#064;XXXX\} と、エスケープ文字が付加されã‚?
277             * ので、このæ–?­—å?を見つけたらã?{&#064;XXXX} に、戻して処ç�?�™るよã�?�«するã€?
278             *
279             * @param       inLine  入力文字å?
280             *
281             * @return      出力文字å?
282             */
283            private String changeHeaderFooterData( final String inLine ) {
284                    int st = inLine.indexOf( "\\{\\@" );
285                    if( st < 0 ) { return inLine; }
286    
287                    StringBuilder buf = new StringBuilder( inLine );
288    
289                    while( st >= 0 ) {
290                            buf.deleteCharAt( st );                 // 初めの '\'
291                            buf.deleteCharAt( st+1 );               // ?‘文字削除してã�?‚‹為ã€?1 番目を削除
292                            int end = buf.indexOf( "\\}",st+2 );
293                            // フォーマットがおかしい場合ã?処ç�?
294                            if( end < 0 ) {
295                                    String errMsg = "こã?ãƒ?ƒ³プレートã? HeaderFooter 部åˆ?? {@XXXX} がã?書式エラーですã?"
296                                                                    + HybsSystem.CR
297                                                                    + inLine ;
298                                    throw new HybsSystemException( errMsg );
299                            }
300                            buf.deleteCharAt( end );                // 初めの '\'
301                            st = buf.indexOf( "\\{\\@",end + 1 );
302                    }
303                    return buf.toString();
304            }
305    
306            /**
307             * 入力文字å? を読み取って、å?力しますã?
308             * å�?‚µブクラスで実è£?�—てくださいã€?
309             *
310             * @param line 入力文字å?
311             */
312            @Override
313            protected void println( final String line ) {
314                    writer.println( line );
315            }
316    
317            /**
318             * {&#064;XXXX}æ–?­—変換後ã?スペã?スをã?&amp;nbsp;と置き換えますã?
319             *
320             * ただしã?式などを使用すると、td タグの属æ?æƒ??に{&#064;XXXX}æ–?­—が含まã‚?
321             * これに、EXCELのスペã?スであるã€?lt;span style="mso-spacerun:
322             * yes"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;
323             * と置き換えると、属æ?リスト中のタグとã�?�†入れ子状態が発生する為ã€?
324             * これは、置き換えませんã€?
325             * &lt;td XXX&gt;YYY&lt;/td&gt; の YYYのç¯?›² を置き換えることになりますã?
326             *
327             * ここではã€?�Ž去の互換性を最大限確保する為に、特殊な方法で、å?ç�?�—ますã?
328             * 前後ã?スペã?スを取り除ã�?�Ÿæ–?­—å?で、かつã€?¼’つ以上ã?連続したスペã?スã�?
329             * 存在する場合ã?み、trim してã€??続スペã?スをã?&amp;nbsp;と置き換えますã?
330             * æ–?­—ã?間に連続スペã?スがなã�??合ã?、前後ã?スペã?スも削除せずにã€?
331             * å…??æ–?­—å?をそのまま返しますã?
332             * 前後ã?スペã?スを変換してしまã�?�¨、数字型の場合に、EXCELでの計算式がエラーになりますã?
333             *
334             * @og.rev 3.5.0.0 (2003/09/17) 新規追åŠ?
335             * @og.rev 3.5.5.0 (2004/03/12) 連続スペã?スの処ç�?‚’EXCELの方式に合わせる
336             * @og.rev 3.6.0.0 (2004/09/17) スペã?ス置き換えã?ã€?td XXX>YYY</td> の YYYのç¯?›²のみとするã€?
337             * @og.rev 3.6.1.0 (2005/01/05) 置換ロジãƒ?‚¯修正(ReplaceString クラスを使用)
338             *
339             * @param       target å…??æ–?­—å?
340             *
341             * @return      置換えた文字å?
342             */
343            private String spaceReplace( final String target ) {
344                    ReplaceString repData = new ReplaceString();
345    
346                    Matcher match1 = PTN1.matcher( target ) ;
347                    while( match1.find() ) {
348                            int st1 = match1.start(1);
349                            String grp1 = match1.group(1);
350                            Matcher match2 = PTN2.matcher( grp1 ) ;
351                            while( match2.find() ) {
352                                    int st2 = match2.start(1);
353                                    String grp2 = match2.group(1);
354                                    Matcher match3 = PTN3.matcher( grp2 ) ;
355                                    while( match3.find() ) {
356    
357                                            int st = st1 + st2 + match3.start(1);
358                                            int ed = st1 + st2 + match3.end(1);
359    
360                                            repData.add( st,ed,makeSpace( ed-st ) );
361                                    }
362                            }
363                    }
364    
365                    String rtn = repData.replaceAll( target );
366    
367                    return rtn ;
368            }
369    
370            /**
371             * æŒ?®šã?個数のスペã?スæ–?­—を表すã?EXCEL の記号を作æ?しますã?
372             *
373             * EXCELでは、スペã?ス?’å?以上をã€?lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;
374             * 形式に置き換えますã?これは、EXCELがHTML変換する時ã?ルールですã?
375             *
376             * ここでは、スペã?スの個数-1 の &amp;nbsp; を持つ、上記ã?æ–?­—å?を作æ?しますã?
377             * æœ?¾Œã?ä¸?�¤は、本物のスペã?ス記号を割り当てますã?
378             *
379             * @og.rev 3.6.0.0 (2004/09/17) 新規追åŠ?
380             *
381             * @param       cnt スペã?スの個数
382             *
383             * @return      置換えた文字å?
384             */
385            private String makeSpace( final int cnt ) {
386                    StringBuilder buf = new StringBuilder( 40 + cnt * 6 );
387                    buf.append( SPACE_ST );
388                    for( int i=1; i<cnt; i++ ) {
389                            buf.append( SPACE );
390                    }
391                    buf.append( SPACE_ED );
392    
393                    return buf.toString();
394            }
395    
396            /**
397             * {&#064;QRCODE.XXXX} を含ã‚?æ–?­—å?の alt 属æ?ã‚?src 属æ?にセãƒ?ƒˆしますã?
398             *
399             * QRコードã?画像を入れ替えるため、alt属æ?に設定してある キーæƒ??をå?にã€?
400             * ?’次å…?ƒ�ーコード画像を作æ?しã?そã?ファイル名を、src 属æ?に設定することでã€?
401             * 動的に画像ファイルのリンクを作æ?しますã?
402             * 現在のEXCELでは、バージョンによってã€?¼’種類ã?画像表示方法が存在するようでã€?
403             * ?‘画像に付きã€?¼’ç®?‰€の変更がå¿?¦�ですã?こã??’ç®?‰€は、変換方法が異なる為ã€?
404             * 全く別の処ç�?‚’行うå¿?¦�がありますã?
405             *
406             * <v:shape ?¥?¥?¥ alt="{&#064;QRCODE.XXXX}" ?¥?¥?¥>
407             *   <v:imagedata src="yyy" ?¥?¥?¥>?¥?¥?¥</v:shape>形式とマッチしã€?
408             * xxx 部åˆ?�¨、yyy 部åˆ?‚’前方参ç?しますã?
409             *
410             * <img ?¥?¥?¥ src="yyy" ?¥?¥?¥ alt="{&#064;QRCODE.XXXX}" ?¥?¥?¥ > 形式とマッチしã€?
411             * yyy 部åˆ?�¨、xxx 部åˆ?‚’前方参ç?しますã?
412             *
413             * 画像ã?エンコードã?、alt属æ?に設定したã?{&#064;QRCODE.XXXX} æ–?­—å?の
414             * XXXX 部åˆ??カラãƒ?ƒ‡ータ(通常、{&#064;XXXX} で取得できる値)を使用しますã?
415             * ãƒ??タが存在しなã�??合ã?、src="yyy" 部を削除することで対応しますã?
416             * なおã?後続å?ç�??関係で、alt="{&#064;QRCODE.XXXX}" æ–?­—å?は、削除しますã?
417             *
418             * @og.rev 3.6.1.0 (2005/01/05) 新規追åŠ?
419             *
420             * @param       target å…??æ–?­—å?
421             *
422             * @return      置換えた文字å?
423             */
424            private String qrcodeReplace( final String target ) {
425                    ReplaceString repData = new ReplaceString();
426    
427                    Matcher match1 = IMGPTN1.matcher( target ) ;
428                    while( match1.find() ) {
429                            String altV = match1.group(1);
430    
431                            int stAlt = match1.start(1) - 9 ;       // {@QRCODE. まで遡ã‚?
432                            int edAlt = match1.end(1)   + 1 ;       // } を含める
433                            repData.add( stAlt,edAlt,"" );          // {@QRCODE.XXXX} の部åˆ?‰Š除
434    
435                            int st = match1.start(2);
436                            int ed = match1.end(2);
437    
438                            String msg = getValue( altV );  // QRコード変換するæ–?­—å?の取å¾?
439                            if( msg != null && msg.length() > 0 ) {
440                                    String newStr = makeQrImage( altV,msg );        // 画像ファイルのファイルå�?
441                                    repData.add( st,ed,newStr );
442                            }
443                            else {
444                                    repData.add( st-5,ed+1,"" );            // src="yyy" 部åˆ??み削除
445                            }
446                    }
447    
448                    Matcher match2 = IMGPTN2.matcher( target ) ;
449                    while( match2.find() ) {
450                            int st = match2.start(1);
451                            int ed = match2.end(1);
452    
453                            String altV = match2.group(2);
454                            int stAlt = match2.start(2) - 9 ;       // {@QRCODE. まで遡ã‚?
455                            int edAlt = match2.end(2)   + 1 ;       // } を含める
456                            repData.add( stAlt,edAlt,"" );          // {@QRCODE.XXXX} の部åˆ?‰Š除
457    
458                            String msg = getValue( altV );  // QRコード変換するæ–?­—å?の取å¾?
459                            if( msg != null && msg.length() > 0 ) {
460                                    String newStr = makeQrImage( altV,msg );        // 画像ファイルのファイルå�?
461                                    repData.add( st,ed,newStr );
462                            }
463                            else {
464                                    repData.add( st-5,ed+1,"" );            // src="yyy" 部åˆ??み削除
465                            }
466                    }
467    
468                    String rtn = repData.replaceAll( target ) ;
469    
470                    return rtn ;
471            }
472    
473            /**
474             * æŒ?®šã?カラãƒ?��と、QRコード変換するæ–?­—å?より、画像を作æ?しますã?
475             *
476             * 返り値は、作æ?した画像ファイルのファイル名ですã?
477             * これは、データが存在しなã�??合に、src="" を返すå¿?¦�があるためã€?
478             * (でなã�?�¨、画像へのリンクが表示されてしまã�??)
479             * src="./帳票ID.files/image00x.png" とã�?�†画像ファイルのアドレス部åˆ?‚’
480             *  {&#064;QRCODE_カラãƒ?��} 形式に変更しておくå¿?¦�がありますã?
481             *
482             * @og.rev 3.6.1.0 (2005/01/05) 新規追åŠ?
483             *
484             * @param       key カラãƒ?��
485             * @param       msg QRコード変換するæ–?­—å?
486             *
487             * @return      画像ファイルのファイルå�?
488             */
489            private String makeQrImage( final String key, final String msg ) {
490                    if( msg == null || msg.length() == 0 ) { return "" ; }
491    
492                    String realClmName = null ;
493                    int sp = key.lastIndexOf( '_' );
494                    if( sp >= 0 ) {
495                            try {
496                                    int row = Integer.parseInt( key.substring( sp+1 ) );
497                                    int realRow = getRealRow( row );
498                                    realClmName = key.substring( 0,sp ) + "_" + realRow ;
499                            }
500                            catch (NumberFormatException e) {       // 4.0.0 (2005/01/31)
501                                    String errMsg = "警告:QRCODE名ã?ヘッãƒ??に'_'カラãƒ?��が使用";
502                                    LogWriter.log( errMsg );
503                            }
504                    }
505                    else {
506                            realClmName = key ;
507                    }
508    
509                    if( qrFileMap == null ) { qrFileMap = new HashMap<String,String>(); }
510                    if( qrFileMap.containsKey( realClmName ) ) {    // Map にすでに存在してã�?‚‹ã€?
511                            return qrFileMap.get( realClmName );
512                    }
513    
514                    // 帳票?©?¤ をå?に、画像ファイルの保存フォルãƒ?‚’求めますã?
515                    String filename    = "./" + listId + ".files/" + realClmName + ".png";
516                    String fullAddress = htmlDir + filename ;
517    
518                    QrcodeImage qrImage = new QrcodeImage();
519                    qrImage.init( msg,fullAddress );
520                    qrImage.saveImage();
521    
522                    qrFileMap.put( realClmName,filename );
523                    return filename;
524            }
525    }