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 java.io.File ;
019import java.io.Writer ;
020import java.io.IOException ;
021
022import javax.xml.transform.dom.DOMSource ;
023import javax.xml.transform.stream.StreamResult ;
024import javax.xml.transform.Transformer ;
025import javax.xml.transform.TransformerFactory ;
026import javax.xml.transform.TransformerException ;
027// import javax.xml.transform.TransformerConfigurationException ;
028import javax.xml.transform.OutputKeys ;
029
030import javax.xml.parsers.DocumentBuilder ;
031import javax.xml.parsers.DocumentBuilderFactory ;
032import javax.xml.parsers.ParserConfigurationException ;
033import org.xml.sax.SAXException ;
034import org.w3c.dom.Document ;
035// import org.opengion.fukurou.system.Closer;                                           // 8.5.4.2 (2024/01/12) PMD 7.0.0 CloseResource 対応
036import org.opengion.fukurou.util.FileUtil;                                                      // 6.3.8.0 (2015/09/11)
037import org.opengion.fukurou.system.ThrowUtil;                                           // 6.4.2.0 (2016/01/29)
038
039/**
040 * XMLファイルを読み取って、Document オブジェクトを取得する、ユーティリティークラスです。
041 *
042 * javax.xml.parsers および、org.w3c.dom の簡易処理を行います。
043 * read で、Document を読み込み、write で、ファイルに書き出します。
044 * なお、書き出しに関しては、UTF-8 固定で、かつ、Transformer で行いますので、
045 * 属性の並び順は、保障されません。(つまり、簡易的な書き出し機能です。)
046 *
047 * @og.rev 5.1.7.0 (2010/06/01) 新規作成
048 *
049 * @version  5.0
050 * @author   Kazuhiko Hasegawa
051 * @since    JDK6.0,
052 */
053
054public final class DomParser {
055
056        /**
057         * デフォルトコンストラクターをprivateにして、
058         * オブジェクトの生成をさせないようにする。
059         */
060        private DomParser() {}
061
062        /**
063         * XMLファイルを読み込み、org.w3c.dom.Documentを返す。
064         *
065         * @og.rev 6.4.2.0 (2016/01/29) ex.printStackTrace() を、ThrowUtil#ogStackTrace(Throwable) に置き換え。
066         *
067         * @param       aFile   XMLファイル
068         *
069         * @return      構築した Document( nullは読み込み失敗 )
070         */
071        public static Document read( final File aFile ) {
072
073                Document document = null;
074                try {
075                        //----------------------------------------------------
076                        // step1. DocumentBuilderを構築する
077                        //----------------------------------------------------
078                        final DocumentBuilderFactory bfactory = DocumentBuilderFactory.newInstance();
079                        final DocumentBuilder builder = bfactory.newDocumentBuilder();
080
081                        //----------------------------------------------------
082                        // step2. XMLファイルを読み込んで、Documentを構築する
083                        //----------------------------------------------------
084                        document = builder.parse( aFile );
085                // 7.2.9.5 (2020/11/28) PMD:'catch' branch identical to 'ParserConfigurationException' branch
086                } catch( final ParserConfigurationException | SAXException | IOException ex) {
087                        System.err.println( ex.getMessage() );
088                        System.err.println( ThrowUtil.ogStackTrace( ex ) );                             // 6.4.2.0 (2016/01/29)
089                }
090//              } catch( final ParserConfigurationException ex) {
091//                      System.err.println( ex.getMessage() );
092//                      System.err.println( ThrowUtil.ogStackTrace( ex ) );                             // 6.4.2.0 (2016/01/29)
093//              } catch( final SAXException ex) {
094//                      // 文法エラーが発生した場合
095//                      System.err.println( ex.getMessage() );
096//                      System.err.println( ThrowUtil.ogStackTrace( ex ) );                             // 6.4.2.0 (2016/01/29)
097//              } catch( final IOException ex) {
098//                      // ファイルが読み込めなかった場合
099//                      System.err.println( ex.getMessage() );
100//                      System.err.println( ThrowUtil.ogStackTrace( ex ) );                             // 6.4.2.0 (2016/01/29)
101//              }
102
103                // 完了
104                return document;
105        }
106
107        /**
108         * Documentを指定ファイルに保存する。
109         *
110         * @param aFile 保存先ファイル
111         * @param aDocument Documentインスタンス
112         *
113         * @og.rev 5.1.9.0 (2010/08/01) Closeされないバグを修正
114         * @og.rev 5.6.6.0 (2013/07/05) 若干のインデックス(らしきもの)を入れます
115         * @og.rev 6.3.8.0 (2015/09/11) FileUtil#getPrintWriter( File,String ) を使用。
116         * @og.rev 6.4.0.2 (2015/12/11) Transformer のエラーを、より詳細に出力します。
117         * @og.rev 6.4.2.0 (2016/01/29) ex.printStackTrace() を、ThrowUtil#ogStackTrace(Throwable) に置き換え。
118         * @og.rev 8.5.4.2 (2024/01/12) PMD 7.0.0 CloseResource 対応
119         */
120        public static void write( final File aFile, final Document aDocument ){
121                final HybsErrorListener errListener = new HybsErrorListener();
122//              Writer out = null;
123//              try {
124                // 8.5.4.2 (2024/01/12) PMD 7.0.0 CloseResource 対応
125                try ( Writer out = FileUtil.getPrintWriter( aFile,"UTF-8" ) ) {         // 6.3.8.0 (2015/09/11)
126                        //---------------------------------
127                        // step1. Transformerの準備
128                        //---------------------------------
129                        final TransformerFactory tFactory = TransformerFactory.newInstance();
130                        // 6.4.0.2 (2015/12/11) TransformerFactory のエラーを、より詳細に出力します。
131                        tFactory.setErrorListener( errListener );
132
133                        final Transformer transformer = tFactory.newTransformer();
134                        // 6.4.0.2 (2015/12/11) Transformer のエラーを、より詳細に出力します。
135                        transformer.setErrorListener( errListener );
136
137                        //---------------------------------
138                        // step2. Transformerの動作設定
139                        //---------------------------------
140                        transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
141                        transformer.setOutputProperty( OutputKeys.METHOD, "xml" );                      // 5.6.6.0 (2013/07/05)
142
143                        // 5.6.6.0 (2013/07/05) インデントを入れるには、OutputKeys.INDENT だけではだめ。
144                        // Xalan の メインの xalan.jarじゃなくて、serializer.jar に入っている OutputPropertiesFactory が必要。
145                        // transformer.setOutputPropert( org.apache.xml.serializer.OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "2" );
146
147                        // この為だけに、また、java の JAVA_HOME/jre/lib/ext を増やすのは嫌なので、OutputPropertiesFactory.S_KEY_INDENT_AMOUNT
148                        // で作成している文字列を直接記述しちゃいます。良い子はマネしないでね。
149                        transformer.setOutputProperty( "{http://xml.apache.org/xalan}indent-amount", "2" );
150
151                        transformer.setOutputProperty( OutputKeys.ENCODING, "UTF-8" );
152
153                        //---------------------------------
154                        // step3. Writerの準備
155                        //---------------------------------
156                        // 6.3.8.0 (2015/09/11) FileUtil#getPrintWriter( File,String ) を使用。
157//                      out = FileUtil.getPrintWriter( aFile,"UTF-8" ) ;                // 6.3.8.0 (2015/09/11)
158
159                        //---------------------------------
160                        // step4. 書き出し
161                        //---------------------------------
162                        transformer.transform( new DOMSource( aDocument ), new StreamResult( out ) );
163                }
164                // 7.2.9.5 (2020/11/28) PMD:'catch' branch identical to 'TransformerConfigurationException' branch
165//              catch( final TransformerConfigurationException ex ) {
166//      //              System.err.println( ex.getMessageAndLocation() );       // 6.4.0.2 (2015/12/11) 行番号がうまく取り出せない。
167//                      System.err.println( errListener.toString() );           // 6.4.0.2 (2015/12/11) エラー内容が重複するかも。
168//                      System.err.println( ThrowUtil.ogStackTrace( ex ) );                             // 6.4.2.0 (2016/01/29)
169//              }
170                catch( final TransformerException ex ) {
171                        // 書き出しエラー発生
172        //              System.err.println( ex.getMessageAndLocation() );       // 6.4.0.2 (2015/12/11) 行番号がうまく取り出せない。
173                        System.err.println( errListener.toString() );           // 6.4.0.2 (2015/12/11) エラー内容が重複するかも。
174                        System.err.println( ThrowUtil.ogStackTrace( ex ) );                             // 6.4.2.0 (2016/01/29)
175                }
176                // 8.5.4.2 (2024/01/12) try-with-resources にしたため、暗黙的な IOException が発生する。
177                catch( final IOException ex ) {
178                        // ファイルがclose できなかった
179                        System.err.println( ex.getMessage() );
180                }
181                // 5.1.9.0 (2010/08/01) Closeされないバグを修正
182//              finally {
183//                      Closer.ioClose( out );
184//              }
185        }
186}