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