    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 */
    016package org.opengion.fukurou.xml;
    017
    018import org.opengion.fukurou.system.OgRuntimeException ;                         // 6.4.2.0 (2016/01/29)
    019import org.opengion.fukurou.system.Closer ;
    020import org.opengion.fukurou.system.DateSet;                                                     // 6.4.2.0 (2016/01/29)
    021import org.opengion.fukurou.system.LogWriter;
    022import org.opengion.fukurou.util.HybsEntry ;
    023import org.opengion.fukurou.util.FileUtil ;
    024import org.opengion.fukurou.util.StringUtil ;
    025import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.1.0.0 (2014/12/26) refactoring
    026import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
    027
    028import java.io.Reader;
    029import java.io.Writer;
    030import java.io.File;
    031import java.io.IOException;
    032import java.io.StringReader;
    033
    034import javax.xml.transform.TransformerException;
    035import javax.xml.transform.TransformerConfigurationException;
    036import javax.xml.transform.TransformerFactory;
    037import javax.xml.transform.Transformer;
    038import javax.xml.transform.stream.StreamSource;
    039import javax.xml.transform.stream.StreamResult;
    040import javax.xml.transform.ErrorListener;                                                       // 6.4.0.2 (2015/12/11)
    041
    042/**
    043 * XML 入力ファイルに、XSL 入力ファイルを適用して、 XSLT変換を行います。
    044 * 結果は、XML 出力ファイルにセーブします。
    045 * 各ファイルの代わりに、Writer,Reader を設定することも可能です。
    046 *
    047 * このパーサーでは、内部で実行中の入力ファイル情報を パラメータとして設定できます。
    048 * useFileInfo( true ) とセットすると、以下の４項目が内部的にセットされます。
    049 * ただし、この設定が可能なのは、XML 入力ファイルに、Reader ではなく、ファイル名を
    050 * 渡した場合のみです。ストリームの場合は、各種情報は取れません。
    051 *
    052 * 入力ファイル(inXMLのフルパス)     : FILEPATH  (例: G:\webapps\gf\jsp\DOC10\query.jsp)
    053 * 入力親フォルダ(inXMLの親フォルダ) : ADDRESS   (例: DOC10)
    054 * 入力ファイル(inXMLのファイル名)   : FILENAME  (例: query.jsp)
    055 * 入力ファイル(inXMLの更新日付  )   : MODIFIED  (例: yyyyMMddHHmmss形式)
    056 *
    057 * xsl ファイルでは、パラメータ は、xsl:param で宣言し、xsl:value-of で取り出します。
    058 * &lt;xsl:param name="ADDRESS" select="" /&gt; と宣言しておき、必要な箇所で
    059 * &lt;xsl:value-of select="$ADDRESS"     /&gt; とすれば、取得できます。
    060 *
    061 *      String inXSTL  = "inXSLfile.xsl" ;   // 入力ＸＳＬファイル
    062 *      String outFile = "outXMLfile.xml" ;  // 出力ＸＭＬファイル
    063 *      String inXML   = "inXMLfile.xml" ;   // 入力ＸＭＬファイル
    064 *
    065 *      XSLT xslt = new XSLT();
    066 *      xslt.setXslFile( inXSTL );
    067 *      xslt.setOutFile( outFile,false );
    068 *
    069 *      xslt.transform( inXML );
    070 *
    071 * @version  4.0
    072 * @author   Kazuhiko Hasegawa
    073 * @since    JDK5.0,
    074 */
    075public class XSLT {
    076        /** 初期 ENCODE 名 {@value}        */
    077        public static final String ENCODE = "UTF-8" ;
    078
    079        private Transformer transformer ;
    080
    081        private String          encode          = ENCODE;
    082        private String          xmlFile         ;
    083        private String          xslFile         ;
    084        private String          outFile         ;
    085        private Reader          xslReader       ;
    086        private Writer          outWriter       ;
    087        private HybsEntry[] paramEntry  ;
    088        private boolean         isFileInfo      ;
    089        private boolean         isErrClose      = true;
    090        private boolean         isErrXmlIn      ;                       // useErrXmlIn ⇒ isErrXmlIn 変更
    091        private boolean         isInclude       = true;         // 4.2.3.0 (2008/05/26)
    092        private StreamResult result             ;
    093
    094        private String          realPath        ;                       // 5.7.6.2 (2014/05/16) 新規追加
    095        private String          debugMsg        ;                       // 5.6.7.1 (2013/08/09) デバッグ用
    096
    097        /**
    098         * 入力XSLファイルを、指定します。
    099         *
    100         * @param       file    入力XSLファイル
    101         * @see #setXslFile( Reader )
    102         */
    103        public void setXslFile( final String file ) {
    104                xslFile = file;
    105                setXslFile( FileUtil.getBufferedReader( new File( xslFile ),encode ) );
    106        }
    107
    108        /**
    109         * 入力XSLリーダーを、指定します。
    110         *
    111         * @param       reader  入力XSLリーダー
    112         * @see #setXslFile( String )
    113         */
    114        public void setXslFile( final Reader reader ) {
    115                transformer = null;
    116                xslReader   = reader;
    117        }
    118
    119        /**
    120         * 結果XML ファイル名と、そのオープン方法を指定します。
    121         * 結果XML ファイルを、追記する(append=true)か新規作成する(append=false)か指定します。
    122         * なお、結果XML ファイル(outFile) を指定しない(=null)か、特別な名称 "System.out"
    123         * 文字列を渡すと、標準出力に 結果を出力します。
    124         *
    125         * @param       file    出力ファイル名(null または、"System.out" 文字列時は、標準出力)
    126         * @param append [true]追記する/false:新規作成する]
    127         */
    128        public void setOutFile( final String file,final boolean append ) {
    129                outFile = file ;
    130                setOutFile( FileUtil.getPrintWriter( new File( outFile ),encode,append ) );
    131        }
    132
    133        /**
    134         * 結果XML データを出力する、Writer を指定します。
    135         * ファイル、標準出力、JSPWriter など、必要に応じて Writer を作成してください。
    136         * 標準出力(System.out)の場合は、NonClosePrintWriter クラスなどの非close()処理系を、
    137         * JSPWriterの場合は、NonFlushPrintWriter クラスなどの非flush()、close()処理系を、
    138         * 使用してください。
    139         *
    140         * @param       writer  出力するWriter
    141         */
    142        public void setOutFile( final Writer writer ) {
    143                Closer.ioClose( outWriter );
    144                outWriter = writer ;
    145                result = new StreamResult( outWriter );
    146        }
    147
    148        /**
    149         * 結果XML ライターに、指定のデータを書き出します。
    150         *
    151         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    152         *
    153         * @param       outData 書き出すデータ
    154         */
    155        public void setOutData( final String outData ) {
    156                if( outData != null && outData.length() > 0 ) {
    157                        // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    158                        if( outWriter == null ) {
    159                                final String errMsg = "#setOutFile(Writer)を先に実行しておいてください。"      + CR
    160                                                                + "   outData =" + outData      + CR;
    161                                throw new OgRuntimeException( errMsg );
    162                        }
    163
    164                        try {
    165                                outWriter.write( outData );
    166                                outWriter.write( CR );
    167                        }
    168                        catch( final IOException ex ) {
    169                                final String errMsg = "ライターにデータ登録を失敗しました。" + CR
    170                                                                + ex.getMessage() ;
    171                                close();
    172                                throw new OgRuntimeException( errMsg,ex );
    173                        }
    174                }
    175        }
    176
    177        /**
    178         * XML ファイルをXSLT変換します。
    179         * XML 入力ファイルに、XSL 入力ファイルを適用して、 XSLT変換を行います。
    180         * 結果は、XML ファイルにセーブします。
    181         * 拡張子が『.jsp』で、かつ、isInclude=true の場合、jsp:directive.include 処理を行います。
    182         *
    183         * @og.rev 4.2.3.0 (2008/05/26) jsp:directive.include 処理の実施可否を引数指定します。
    184         * @og.rev 5.2.1.0 (2010/10/01) JspIncludeReader#getString の第３引数を廃止
    185         * @og.rev 5.6.7.1 (2013/08/09) デバッグ用に、ファイルリストを取得しておきます。
    186         * @og.rev 5.7.6.2 (2014/05/16) #transform( String , boolean ) 廃止。realPath 追加
    187         *
    188         * @param       file    入力XMLファイル
    189         */
    190        public void transform( final String file ) {
    191                xmlFile = file;
    192
    193                if( xmlFile.endsWith( ".jsp" ) && isInclude ) {
    194                        // 5.6.7.1 (2013/08/09) デバッグ用に、ファイルリストを取得しておきます。
    195                        final JspIncludeReader incReader = new JspIncludeReader();
    196                        incReader.setRealPath( realPath );                              // 5.7.6.2 (2014/05/16) realPath 追加
    197                        debugMsg = incReader.getIncludeFiles();
    198
    199                        final String incData = incReader.getString( new File( xmlFile ),encode );                               // 5.2.1.0 (2010/10/01)
    200                        transform( new StringReader( incData ) );
    201                }
    202                else {
    203                        transform( FileUtil.getBufferedReader( new File( xmlFile ),encode ) );
    204                }
    205        }
    206
    207        /**
    208         * XML ファイルをXSLT変換します。
    209         * XML 入力リーダーに、XSL 入力リーダーを適用して、 XSLT変換を行います。
    210         * 結果は、XML ライターに書き出します。
    211         * この処理の終了後に、入力XML リーダー は、close() されます。
    212         *
    213         * @og.rev 5.6.5.2 (2013/06/21) エラーメッセージが判りにくいので、追記します。
    214         * @og.rev 5.6.7.1 (2013/08/09) デバッグ用に、ファイルリストを出力します。
    215         * @og.rev 6.4.0.2 (2015/12/11) Transformer のエラーを、より詳細に出力します。
    216         *
    217         * @param       xmlReader       入力XML リーダー
    218         * @see #transform( String )
    219         */
    220        public void transform( final Reader xmlReader ) {
    221                HybsEntry[] entry = null;
    222
    223                // transformer は使いまわしますが、ErrorListener は、Reader 毎に再作成します。
    224                final ErrorListener errListener = new HybsErrorListener();                      // 6.4.0.2 (2015/12/11)
    225                try {
    226                        if( transformer == null ) {
    227                                init( errListener );                                                                            // 6.4.0.2 (2015/12/11)
    228                        }
    229                        else {
    230                                transformer.reset();
    231                                transformer.setErrorListener( errListener );                            // 6.4.0.2 (2015/12/11)
    232                        }
    233
    234                        // 入力XMLファイルのファイル情報を設定します。
    235                        if( isFileInfo && xmlFile != null ) {
    236                                entry = getXmlParameter( xmlFile );
    237                                parameterSet( transformer,entry );
    238                        }
    239                        xmlFile = null ;
    240
    241                        // 入力XMLリーダーからStreamSourceを作る
    242                        final StreamSource data = new StreamSource( xmlReader );
    243
    244                        transformer.transform( data,result );
    245                }
    246                catch( final TransformerException ex ) {
    247                        // 5.7.3.0 (2014/02/07) エラー情報をもう少し詳細に取得します。
    248        //              final String errMsg = ex.getMessageAndLocation() ;
    249                        final String errMsg = errListener.toString();                                   // 6.4.0.2 (2015/12/11) さらに詳細に出します。
    250
    251                        final StringBuilder errBuf = new StringBuilder( BUFFER_MIDDLE )
    252                                .append( "=====================================================" ).append( CR )
    253                                .append( "XML-XSLT 変換に失敗しました。" ).append( CR )
    254                                .append( errMsg );
    255
    256                        // 6.3.1.0 (2015/06/28) デバッグ用メッセージを出力します。
    257                        if( debugMsg != null && debugMsg.length() > 0 ) {
    258                                errBuf.append( CR ).append( debugMsg );
    259                        }
    260
    261                        // 5.6.5.2 (2013/06/21) エラーメッセージが判りにくいので、追記します。
    262                        if( errMsg.indexOf( "プロローグにはコンテンツを指定できません" ) >= 0 ) {
    263                                errBuf.append( CR ).append( "\t(UTF-8変換時に、BOMが付くとこのエラーが出ます。BOMを外してみてください。)" );
    264                        }
    265
    266                        // 5.6.7.1 (2013/08/09) デバッグ用に、ファイルリストを出力します。
    267                        if( errMsg.indexOf( "で終了する必要があります" ) >= 0 ) {
    268                                errBuf.append( CR ).append( "\t(不整合は、includeファイルの可能性があります。)" );
    269                        }
    270                        errBuf.append( CR );
    271
    272                        if( isErrXmlIn ) { setOutData( toXmlRow( entry, ex ) ); }
    273
    274                        if( isErrClose ) { close(); }
    275                        throw new OgRuntimeException( errBuf.toString(),ex );
    276                }
    277                finally {
    278                        Closer.ioClose( xmlReader );
    279                }
    280        }
    281
    282        /**
    283         * Transformer オブジェクトに対して、Parameter を設定します。
    284         *
    285         * 指定されたパラメーターキーは、xsl ファイルでは、xsl:param で宣言し、
    286         * xsl:value-of で取り出します。
    287         * &lt;xsl:param name="ADDRESS" select="" /&gt; と宣言しておき、必要な箇所で
    288         * &lt;xsl:value-of select="$ADDRESS"     /&gt; とすれば、取得できます。
    289         *
    290         * @param       entry   HybsEntry配列(可変長引数)
    291         */
    292        public void setParamEntry( HybsEntry... entry ) {
    293                if( entry != null && entry.length > 0 ) {               // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    294                        paramEntry = new HybsEntry[entry.length];
    295                        System.arraycopy( entry,0,paramEntry,0,entry.length );
    296                }
    297        }
    298
    299        /**
    300         * transform 処理中にエラーが発生した場合に、出力ファイルを閉じるかどうかを指定します。
    301         *
    302         * 処理途中でエラーが発生した場合に、そこで処理を中断するか、それとも、
    303         * 無視して、さらに処理を進めるかを指定することが可能です。
    304         * 継続して処理を進めたい場合は、出力ファイルを閉じないため、false を
    305         * 設定します。ただし、エラー時には、RuntimeException は throw されます。
    306         * 初期値は、true(閉じる)です。
    307         *
    308         * @param       flag    エラー時クローズ [true:閉じる/false:閉じない]
    309         */
    310        public void errClose( final boolean flag ) {
    311                isErrClose = flag ;
    312        }
    313
    314        /**
    315         * transform 処理中エラーを、出力ファイルに、XML形式でエラーを追記するかどうかを指定します。
    316         *
    317         * 処理途中でエラーが発生した場合に、ログだけではなく、結果XMLファイルに、
    318         * エラー内容や、エラーファイルなどを埋め込むと、XMLファイルとしてDB登録や、
    319         * その他集計等に使えます。
    320         * 今は、GE70 スキーマ形式のファイルしか作成できません。
    321         * これは、#errClose( boolean ) メソッドと共に使用すると効果的です。
    322         * つまり、errClose = false; にして、エラー時でも出力ファイルを閉じずに、
    323         * 処理を続ける事で、エラーメッセージもXMLファイルとして蓄積できます。
    324         * 初期値は、false(使用しない)です。
    325         *
    326         * @param       flag    エラー時XML形式 [false:使用しない/true:使用する]
    327         */
    328        public void useErrXmlIn( final boolean flag ) {
    329                isErrXmlIn = flag ;
    330        }
    331
    332        /**
    333         * jsp:directive.include 発見時に、そのファイルを INCLUDE するかを指定するかどうかを指定します(初期値:true:使用する)
    334         *
    335         * 引数の処理対象ファイル(transformの引数ファイル)が、『.jsp』の場合、
    336         * jsp:directive.include 発見時に、そのファイルを INCLUDE するかを指定するか
    337         * どうかを指定します。
    338         * インクルードされたファイルとあわせて、正規のXML にならないと、パーサー
    339         * エラーが発生します。
    340         * JSPソース解析を行うには、INCLUDE ファイルも考慮しないと正確な結果を
    341         * 得られませんが、INCLUDE 先のファイルまで合わせる必要があるため、
    342         * 場合によっては、INCLUDEファイルを無視しなければならないケースがあります。
    343         * 初期値は、true(使用する)です。
    344         *
    345         * @param       flag    エラー時XML形式 [false:使用しない/true:使用する]
    346         */
    347        public void jspInclude( final boolean flag ) {
    348                isInclude = flag ;
    349        }
    350
    351        /**
    352         * jspInclude=true 時に、/jsp/common/** 等の include ファイルが存在しない場合の共有取得場所を指定します。
    353         *
    354         * 引数の処理対象ファイル(transformの引数ファイル)が、『.jsp』で、かつ、jspInclude=true の場合、
    355         * そのファイルを INCLUDE するのですが、/jsp/common/** 等の include ファイルは、
    356         * エンジン共通として、jspCommon6.x.x.x.jar で提供しています。
    357         * 従来は、処理対象jspの相対パスで、../../../gf/jsp/commom/** を取り込んでいましたが、
    358         * Tomcat起動フォルダ以外のシステムのJSPチェックなどを行う場合は、gf フォルダが存在しない
    359         * ケースがあります。
    360         * そこで、確実にgf が存在する、処理をキックしている環境の gf を使用するように変更します。
    361         * その環境とは、つまり、エンジン内部変数の REAL_PATH ですが、jsp などが実行していないと取得できません。
    362         *
    363         * @param       path    /jsp/common/** 等の include ファイルの共有取得場所
    364         */
    365        public void setRealPath( final String path ) {
    366                realPath = path ;
    367        }
    368
    369        /**
    370         * 入力XSLファイルのストリームを閉じます。
    371         *
    372         * @og.rev 5.6.7.1 (2013/08/09) includeしたファイルのキャッシュをクリアします。
    373         */
    374        public void close() {
    375                Closer.ioClose( outWriter );
    376
    377                // 5.6.7.1 (2013/08/09) includeしたファイルのキャッシュをクリア
    378                JspIncludeReader.cacheClear();
    379        }
    380
    381        /**
    382         * XML ファイルをXSLT変換します。
    383         * XML 入力ファイルに、XSL 入力ファイルを適用して、 XSLT変換を行います。
    384         * 結果は、XML ファイルにセーブします。
    385         * なお、結果XML ファイル(outFile) に、特別な名称 "System.out" 文字列を渡すと、
    386         * 標準出力に 結果を出力します。
    387         *
    388         * @og.rev 5.6.7.1 (2013/08/09) includeしたファイルのキャッシュをクリアします。
    389         * @og.rev 6.4.0.2 (2015/12/11) Transformer のエラーを、より詳細に出力します。
    390         *
    391         * @param       errListener ErrorListenerオブジェクト
    392         */
    393        private void init( final ErrorListener errListener ) {
    394                try {
    395                        // xsl属性からStreamSourceを作る
    396                        final StreamSource style = new StreamSource( xslReader );
    397
    398                        // Transformerを作り、XMLを変換する
    399                        final TransformerFactory tFactory = TransformerFactory.newInstance();
    400
    401                        // 6.4.0.2 (2015/12/11) Transformer のエラーを、より詳細に出力します。
    402                        tFactory.setErrorListener( errListener );
    403
    404                        transformer = tFactory.newTransformer( style );
    405                        // 6.4.0.2 (2015/12/11) Transformer のエラーを、より詳細に出力します。
    406                        transformer.setErrorListener( errListener );
    407
    408                        parameterSet( transformer,paramEntry );
    409
    410                        // 5.6.7.1 (2013/08/09) includeしたファイルのキャッシュをクリア
    411                        JspIncludeReader.cacheClear();
    412                }
    413                catch( final TransformerConfigurationException ex ) {
    414                        final String errMsg = xslFile + "ファイルの XSLT 解析に失敗しました。" + CR
    415        //                                                      + ex.getMessageAndLocation()    // 6.4.0.2 (2015/12/11) 行番号がうまく取り出せない。
    416                                                                + errListener.toString();               // 6.4.0.2 (2015/12/11) エラー内容が重複するかも。
    417                        throw new OgRuntimeException( errMsg,ex );
    418                }
    419                finally {
    420                        Closer.ioClose( xslReader );
    421                        xslReader = null;
    422                }
    423        }
    424
    425        /**
    426         * 実行中の入力ファイル名などの属性情報を パラメータとして設定するかどうかを指定します。
    427         *
    428         * このパーサーでは、内部で実行中の入力ファイル情報を パラメータとして設定できます。
    429         * useFileInfo( true ) とセットすると、以下の４項目が内部的にセットされます。
    430         *
    431         * 入力ファイル(inXMLのフルパス)     : FILEPATH  (例: G:\webapps\gf\jsp\DOC10\query.jsp)
    432         * 入力親フォルダ(inXMLの親フォルダ) : ADDRESS   (例: DOC10)
    433         * 入力ファイル(inXMLのファイル名)   : FILENAME  (例: query.jsp)
    434         * 入力ファイル(inXMLの更新日付  )   : MODIFIED  (例: yyyyMMddHHmmss形式)
    435         *
    436         * @og.rev 4.0.0.0 (2007/09/25) ParameterMetaData を使用したパラメータ設定追加。
    437         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
    438         *
    439         * xsl ファイルでは、xsl:param で宣言し、xsl:value-of で取り出します。
    440         * &lt;xsl:param name="ADDRESS" select="" /&gt; と宣言しておき、必要な箇所で
    441         * &lt;xsl:value-of select="$ADDRESS"     /&gt; とすれば、取得できます。
    442         *
    443         * 初期値は、false(セットしない) です。
    444         *
    445         * @param       flag    セットする:true/セットしない:false
    446         */
    447        public void useFileInfo( final boolean flag ) {
    448                isFileInfo = flag;
    449        }
    450
    451        /**
    452         * ファイル名指定で XML,XSL,OUTファイルを指定する場合のエンコードを指定します。
    453         *
    454         * 初期値は、UTF-8 です。
    455         *
    456         * @param       encode  エンコード
    457         */
    458        public void useEncode( final String encode ) {
    459                this.encode = encode;
    460        }
    461
    462        /**
    463         * 実行中の入力ファイル名などの属性情報を パラメータとして取得します。
    464         *
    465         * 入力ファイル(inXMLのフルパス)     : FILEPATH  (例: G:\webapps\gf\jsp\DOC10\query.jsp)
    466         * 入力ファイル(inXMLのファイル名)   : FILENAME  (例: query.jsp)
    467         * 入力親フォルダ(inXMLの親フォルダ) : ADDRESS   (例: DOC10)
    468         * 入力ファイル(inXMLの更新日付  )   : MODIFIED  (例: yyyyMMddHHmmss形式)
    469         *
    470         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
    471         *
    472         * @param       xmlIn   XML入力ファイル
    473         *
    474         * @return      HybsEntry配列
    475         */
    476        private HybsEntry[] getXmlParameter( final String xmlIn ) {
    477                HybsEntry[] entry = new HybsEntry[4] ;
    478
    479                entry[0] = new HybsEntry( "FILEPATH" , xmlIn) ;
    480
    481                final File xmlFile = new File( xmlIn );
    482                entry[1] = new HybsEntry( "FILENAME" , xmlFile.getName()) ;
    483
    484                final File parentFile = xmlFile.getParentFile() ;
    485                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
    486                entry[2] = parentFile == null
    487                                                ? new HybsEntry( "ADDRESS"  , "" )
    488                                                : new HybsEntry( "ADDRESS"  , parentFile.getName()) ;
    489
    490                final String lastDate = DateSet.getDate( xmlFile.lastModified() , "yyyyMMddHHmmss" ) ;          // 5.5.7.2 (2012/10/09) HybsDateUtil を利用
    491                entry[3] = new HybsEntry( "MODIFIED" , lastDate ) ;
    492
    493                return entry ;
    494        }
    495
    496        /**
    497         * Transformer オブジェクト に、パラメータを設定します。
    498         *
    499         * 指定されたパラメーターキーは、xsl ファイルでは、xsl:param で宣言し、
    500         * xsl:value-of で取り出します。
    501         * <xsl:param name="ADDRESS" select="" /> と宣言しておき、必要な箇所で
    502         * <xsl:value-of select="$ADDRESS"     /> とすれば、取得できます。
    503         *
    504         * @param former Transformerオブジェクト
    505         * @param entry  パラメータ配列(可変長引数)
    506         */
    507        private void parameterSet( final Transformer former,final HybsEntry... entry ) {
    508                if( entry != null && entry.length > 0 ) {               // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    509                        final int size   = entry.length;
    510                        for( int i=0; i<size; i++ ) {
    511                                final String key = entry[i].getKey() ;
    512                                final String val = entry[i].getValue();
    513                                former.setParameter( key , val );
    514                        }
    515                }
    516        }
    517
    518        /**
    519         * このオブジェクトの内部文字列表現を返します。
    520         *
    521         * 接続URL + "," + 接続ユーザー + " (" + 作成日付 + ")" です。
    522         *
    523         * @return 内部文字列表現
    524         * @og.rtnNotNull
    525         */
    526        @Override
    527        public String toString() {
    528                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
    529                        .append( "XSL File:" ).append( xslFile ).append( CR )
    530                        .append( "XML File:" ).append( xmlFile ).append( CR )
    531                        .append( "OUT File:" ).append( outFile ).append( CR );
    532
    533                return buf.toString() ;
    534        }
    535
    536        /**
    537         * エラー情報の内部XML文字列表現を返します。
    538         *
    539         * エラー時の情報も、XML化して保存する為の簡易処理。
    540         * ここでは、XMLスキーマは、固定で、GF70 の形式になります。
    541         *
    542         * @og.rev 4.2.3.0 (2008/05/26) エラー発生時のXMLファイルを追加します。
    543         * @og.rev 5.2.1.0 (2010/10/01) XML形式を変更します。(TEXT⇒TEXT_DATA)
    544         *
    545         * @param       entry   HybsEntry配列
    546         * @param       ex              エラー情報
    547         *
    548         * @return XMLの部分文字列
    549         * @og.rtnNotNull
    550         */
    551        private String toXmlRow( final HybsEntry[] entry,final TransformerException ex ) {
    552                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    553
    554                // 6.0.2.5 (2014/10/31) char を append する。
    555                buf.append( "<ROW>" ).append( CR );
    556                if( paramEntry != null ) {
    557                        for( int i=0; i<paramEntry.length; i++ ) {
    558                                final String key = paramEntry[i].getKey() ;
    559                                final String val = paramEntry[i].getValue();
    560                                buf.append( "  <" ).append( key ).append( '>' )
    561                                        .append( val )
    562                                        .append( "</" ).append( key ).append( '>' )
    563                                        .append( CR );
    564                        }
    565                }
    566
    567                if( entry != null ) {
    568                        for( int i=0; i<entry.length; i++ ) {
    569                                final String key = entry[i].getKey() ;
    570                                final String val = entry[i].getValue();
    571                                buf.append( "  <" ).append( key ).append( '>' )
    572                                        .append( val )
    573                                        .append( "</" ).append( key ).append( '>' )
    574                                        .append( CR );
    575                        }
    576                }
    577
    578                buf.append( "  <TAGNAME />" ).append( CR )                                              // XML なので、このまま。
    579                        .append( "  <MSGCD>XML_ERROR</MSGCD>" ).append( CR )
    580                        .append( "  <MSGTXT>XML-XSLT 変換に失敗しました。</MSGTXT>" ).append( CR );
    581
    582                String errMsg = StringUtil.htmlFilter( ex.getMessage() );
    583                final int indx = errMsg.lastIndexOf( "Exception:" );
    584                if( indx >= 0 ) {
    585                        errMsg = errMsg.substring( indx + "Exception:".length() );
    586                }
    587                buf.append( "  <TEXT_DATA>" ).append( errMsg ).append( CR )             // 5.2.1.0 (2010/10/01)
    588                        .append( " Location:" ).append( ex.getLocationAsString() ).append( CR )
    589                        .append( "</TEXT_DATA>" ).append( CR )          // 5.2.1.0 (2010/10/01)
    590                        .append( "</ROW>" ).append( CR );
    591
    592                return buf.toString() ;
    593
    594/*
    595           <ROW>
    596                 <SYSTEM_ID>  </SYSTEM_ID>
    597                 <ADDRESS  >  </ADDRESS>
    598                 <FILENAME >  </FILENAME>
    599                 <FILEPATH >  </FILEPATH>
    600                 <MODIFIED >  </MODIFIED>
    601                 <TAGNAME  >  </TAGNAME>
    602                 <MSGCD    >  </MSGCD>
    603                 <MSGTXT   >  </MSGTXT>
    604                 <TEXT_DATA>  </TEXT_DATA>
    605           </ROW>
    606*/
    607        }
    608
    609        /**
    610         * テスト用のメインメソッド。
    611         *
    612         * java org.opengion.fukurou.xml.XSLT in_xml in_xsl out_xml
    613         *
    614         * @param       args    コマンド引数配列
    615         * @throws IOException 入出力エラーが発生した場合
    616         */
    617        public static void main( final String[] args ) throws IOException {
    618                if( args.length != 3 ) {
    619                        LogWriter.log( "Usage: java org.opengion.fukurou.xml.XSLT in_xml in_xsl out_xml" );
    620                        LogWriter.log( "  XML 入力ファイルに、XSL 入力ファイルを適用して、" );
    621                        LogWriter.log( "  XSLT変換を行います。" );
    622                        LogWriter.log( "  結果は、XML ファイルにセーブします。" );
    623                        LogWriter.log( "  out_xml に System.out を指定すると標準出力に出力します。" );
    624                        return ;
    625                }
    626
    627                final XSLT xslt = new XSLT();
    628                xslt.setXslFile( args[1] );
    629                xslt.setOutFile( args[2],false );
    630                xslt.transform( args[0] );
    631                xslt.close();
    632        }
    633}