プログラミング・ノウハウ集 〜 JAVA 編 (1)

JavaとXMLファイルのデータ連携

  1. XMLファイルを扱うクラスの定義
  2. 単独のデータの場合
  3. 複数のデータの場合

  1. XMLファイルを扱うクラスの定義
  2. プログラム内でデータを定数的に使いたいシーンはよくあると思います。
    たとえばデータベースの接続情報、ログファイルの出力先フォルダやファイル名、ファイルやデータベースの状態を見に行く時間の設定、などなど・・・。
    このような時、Windowsアプリケーションでは、設定ファイル(iniファイル)やレジストリに保存していました。
    Windowsでは iniファイルやレジストリへの読み書きをサポートした関数群があるので、ほかの形式の設定ファイルよりもプログラミングの負担が小さいのです。

    一方、必ずしもWindows上で動かされるとは限らないJavaの場合、よく設定ファイルの形式で使われるのが、XMLファイルと呼ばれるものです。
    Javaの場合、レジストリはもとより、iniファイルに読み書きするよりは、XMLファイルに読み書きしたほうが、プログラミングの負担が小さくなるのです。
    XMLファイルは HTMLファイルと同じように、<xxx>...</xxx>のようなタグで項目名、データを管理します。

    サンプル

    iniファイル
    
    [root]
    jdbcDriver=org.postgresql.Driver
    user=usr
    password=pass
    url=jdbc:postgresql://192.168.xxx.yyy:zzzz/pg
    maxActive=10
    maxIdle=10
    
    XMLファイル
    
    <?xml version = "1.0" encoding = "Shift_JIS" ?>
    
    <root>
    <jdbcDriver>org.postgresql.Driver</jdbcDriver>
    <user>usr</user>
    <password>pass</password>
    <url>jdbc:postgresql://192.168.xxx.yyy:zzzz/pg</url>
    <maxActive>10</maxActive>
    <maxIdle>10</maxIdle>
    
    </root>
    
    

    XMLファイルへの読み書きを容易にしているのが XMLDecoderクラス、およびXMLEncoderクラスです。
    XMLファイルからJavaのデータクラスに読み出すのが XMLDecoderクラス、XMLファイルの形式に変換して出力するのが XMLEncoderクラスの役割です。

    ためしに、XMLファイル名とオブジェクトを渡すと自動的にXMLファイルに書き出したり、逆に呼び出しただけでXMLファイルからデータクラスに読み出すためだけのクラスを作ってみました。

    サンプルプログラム

    xml/XMLStream.java
    
    package xml;
    
    import java.beans.XMLDecoder;
    import java.beans.XMLEncoder;
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    
    public class XMLStream {
    
        /* XMLファイル */
        private String  _strFile;
    
        /**
         * コンストラクタ。XMLファイル名を指定する。
         * @param strFile   XMLファイル名
         */
        public XMLStream( String strFile ) {
    
            this._strFile = strFile;
        }
    
        /**
         * オブジェクトデータをXMLに出力する。
         * @param objBean   XMLに書き込む内容を含むオブジェクト
         */
        public void writeXML(Object objBean) {
    
            try {
                /* オブジェクトからXMLへの変換オブジェクトを生成する。 */
                XMLEncoder xmlEncoder = new XMLEncoder(
                    new BufferedOutputStream(
                        new FileOutputStream(this._strFile)));
                /* 指定したXMLファイルにオブジェクトデータを書き込む。 */
                xmlEncoder.writeObject(objBean);
                /* 変換オブジェクトを閉じる。 */
                xmlEncoder.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * オブジェクトにXMLデータを入力する。
         * @return  XMLデータを格納したオブジェクト
         */
        public Object readXML() {
    
            Object objBean = null;
    
            try {
                /* XMLからオブジェクトへの変換オブジェクトを生成する。 */
                XMLDecoder xmlDecoder = new XMLDecoder(
                    new BufferedInputStream(
                        new FileInputStream(this._strFile)));
                /* 指定したXMLファイルからオブジェクトにデータを読み込む。 */
                objBean = xmlDecoder.readObject();
                /* 変換オブジェクトを閉じる。 */
                xmlDecoder.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
    
            return objBean;
        }
    }
    
    

    なお、今回のサンプルで使うデータクラスは下のようなものです。
    データ型に関しては、実際にはもっと適したものがあるものもありますが、今回はなるべく多くのデータ型を使うという方針でクラスを作成したので、そのあたりはご容赦ください。

    サンプルプログラム

    xmlSample/ObjectSample.java
    
    package xmlSample;
    
    /**
     * XMLファイルへの読み書きサンプル用オブジェクト
     */
    public class ObjectSample {
    
        /** 名前 */
        String  _strName;
        /** 性別 */
        char    _chrGender;
        /** 身長 */
        double  _dblHeight;
        /** 体重 */
        float   _fltWeight;
        /** 種族 */
        byte    _bytRace;
        /** レベル */
        short   _shtLevel;
        /** 年齢 */
        int     _intAge;
        /** 経験値 */
        long    _lngExp;
        /** 未婚フラグ */
        boolean _blnSingle;
    
        /**
         * コンストラクタ
         */
        public ObjectSample() {
        }
    
        /**
         * 全項目をセットする。
         * @param strName   名前
         * @param chrGender 性別
         * @param dblHeight 身長
         * @param fltWeight 体重
         * @param bytRace   種族
         * @param shtLevel  レベル
         * @param intAge    年齢
         * @param lngExp    経験値
         * @param blnSingle 未婚フラグ
         */
        public ObjectSample(
            String  strName,
            char    chrGender,
            double  dblHeight,
            float   fltWeight,
            byte    bytRace,
            short   shtLevel,
            int     intAge,
            long    lngExp,
            boolean blnSingle) {
    
            setName     (strName);
            setGender   (chrGender);
            setHeight   (dblHeight);
            setWeight   (fltWeight);
            setRace     (bytRace);
            setLevel    (shtLevel);
            setAge      (intAge);
            setExp      (lngExp);
            setSingle   (blnSingle);
    
        }
        /**
         * 名前を設定する。
         * @param strName   名前
         */
        public void setName( String strName ) {
            this._strName = strName;
        }
        /**
         * 名前を取得する。
         * @return  名前
         */
        public String getName() {
            return this._strName;
        }
        /**
         * 性別を設定する。
         * @param chrGender 性別
         */
        public void setGender( char chrGender ) {
            this._chrGender = chrGender;
        }
        /**
         * 性別を取得する
         * @return  性別
         */
        public char getGender() {
            return this._chrGender;
        }
        /**
         * 身長を設定する。
         * @param dblHeight 身長
         */
        public void setHeight( double   dblHeight ) {
            this._dblHeight = dblHeight;
        }
        /**
         * 身長を取得する。
         * @return  身長
         */
        public double getHeight() {
            return this._dblHeight;
        }
        /**
         * 体重を設定する。
         * @param fltWeight 体重
         */
        public void setWeight( float    fltWeight ) {
            this._fltWeight = fltWeight;
        }
        /**
         * 体重を取得する。
         * @return  体重
         */
        public float getWeight() {
            return this._fltWeight;
        }
        /**
         * 種族を設定する。
         * @param bytRace   種族
         */
        public void setRace( byte   bytRace ) {
            this._bytRace = bytRace;
        }
        /**
         * 種族を取得する。
         * @return  種族
         */
        public byte getRace() {
            return this._bytRace;
        }
        /**
         * レベルを設定する。
         * @param shtLevel  レベル
         */
        public void setLevel( short shtLevel ) {
            this._shtLevel = shtLevel;
        }
        /**
         * レベルを取得する。
         * @return  レベル
         */
        public short getLevel() {
            return this._shtLevel;
        }
        /**
         * 年齢を設定する。
         * @param intAge    年齢
         */
        public void setAge( int     intAge ) {
            this._intAge = intAge;
        }
        /**
         * 年齢を取得する。
         * @return  年齢
         */
        public int   getAge() {
            return this._intAge;
        }
        /**
         * 経験値を設定する。
         * @param lngExp    経験値
         */
        public void setExp( long    lngExp ) {
            this._lngExp = lngExp;
        }
        /**
         * 経験値を取得する。
         * @return  経験値
         */
        public long getExp() {
            return this._lngExp;
        }
        /**
         * 未婚フラグを設定する。
         * @param blnSingle 未婚フラグ
         */
        public void setSingle( boolean  blnSingle ) {
            this._blnSingle = blnSingle;
        }
        /**
         * 未婚フラグを取得する。
         * @return  未婚フラグ
         */
        public boolean getSingle() {
            return this._blnSingle;
        }
    }
    
    

  3. 単独のデータの場合
  4. たとえば1人分の情報だけを管理したらすむような場合、ただ単純にデータクラスのオブジェクトを生成して、そのインスタンスを使ってファイルを読み書きすれば事足ります。

    サンプルプログラム

    xmlTest/XMLTester.java (main メソッド)
    
    package xmlTest;
    
    import xml.XMLStream;
    import xmlSample.ObjectSample;
    
    public class XMLTester {
    
        final static String FILE_NAME = "test.xml";
    
        public static void main( String[] args ) {
    
            XMLStream xmlStream = new XMLStream(FILE_NAME);
            ObjectSample    objSample = new ObjectSample("ティア・マナリス",'F',147.3, 39.6F, (byte)4, (short)7, 49, 5400, true);
    
            xmlStream.writeXML(objSample);
    
        }
    
    }
    
    

    上のようなプログラムを作成して実行すると、下のようなXMLファイルが作成されます。

    出力結果

    test.xml
    
    <?xml version="1.0" encoding="UTF-8"?>
    <java version="1.5.0_07" class="java.beans.XMLDecoder">
     <object class="xml.ObjectSample">
      <void property="age">
       <int>49</int>
      </void>
      <void property="exp">
       <long>5400</long>
      </void>
      <void property="gender">
       <char>F</char>
      </void>
      <void property="height">
       <double>147.3</double>
      </void>
      <void property="level">
       <short>7</short>
      </void>
      <void property="name">
       <string>ティア・マナリス</string>
      </void>
      <void property="race">
       <byte>4</byte>
      </void>
      <void property="single">
       <boolean>true</boolean>
      </void>
      <void property="weight">
       <float>39.6</float>
      </void>
     </object>
    </java>
    
    

    このファイルを読み込むときは、データクラスのインスタンスを生成して、XMLファイル読み込みメソッドの戻り値をそこにすると、項目名に従ってデータが格納されていきます。

    サンプルプログラム

    xmlTest/XMLTester.java (main メソッド)
    
    package xml;
    
    public class XMLTester {
    
        final static String FILE_NAME = "test.xml";
    
        public static void main( String[] args ) {
    
            XMLStream xmlStream = new XMLStream(FILE_NAME);
            ObjectSample    objSample = (ObjectSample)xmlStream.readXML();
    
            System.out.println( "Name   = " + objSample.getName());
            System.out.println( "Gender = " + objSample.getGender());
            System.out.println( "Height = " + objSample.getHeight());
            System.out.println( "Weight = " + objSample.getWeight());
            System.out.println( "Race   = " + objSample.getRace());
            System.out.println( "Level  = " + objSample.getLevel());
            System.out.println( "Age    = " + objSample.getAge());
            System.out.println( "Exp    = " + objSample.getExp());
            System.out.println( "Single = " + objSample.getSingle());
    
        }
    
    }
    
    

    出力結果

    
    Name   = ティア・マナリス
    Gender = F
    Height = 147.3
    Weight = 39.6
    Race   = 4
    Level  = 7
    Age    = 49
    Exp    = 5400
    Single = true
    
    

  5. 複数のデータの場合
  6. では、複数の人の分だけ情報を管理する必要がある場合は、どのようにしたらいいのでしょう?
    答えは簡単。ただ単純にデータクラスのオブジェクトを配列で生成すればOKです。
    配列のままXMLファイル出力メソッドに設定すれば、XMLファイルにもそのように出力されます。

    サンプルプログラム

    xmlTest/XMLTester.java (main メソッド)
    
    package xml;
    
    public class XMLTester {
    
        final static String FILE_NAME = "test.xml";
    
        public static void main( String[] args ) {
    
            XMLStream xmlStream = new XMLStream(FILE_NAME);
            ObjectSample    objSample[] = {
                new ObjectSample("ティア・マナリス",'F',147.3, 39.6F, (byte)4, (short)7, 49, 5400, true),
                new ObjectSample("エリス",'F',151.6, 38.8F, (byte)1, (short)8, 293, 7300, false),
                new ObjectSample("デリック・ラプター",'M',173.4, 69.2F, (byte)0, (short)2, 27, 2100, true)};
    
            xmlStream.writeXML(objSample);
    
        }
    
    }
    
    

    出力結果

    test.xml
    
    <?xml version="1.0" encoding="UTF-8"?>
    <java version="1.5.0_07" class="java.beans.XMLDecoder">
     <array class="xml.ObjectSample" length="3">
      <void index="0">
       <object class="xml.ObjectSample">
        <void property="age">
         <int>49</int>
        </void>
        <void property="exp">
         <long>5400</long>
        </void>
        <void property="gender">
         <char>F</char>
        </void>
        <void property="height">
         <double>147.3</double>
        </void>
        <void property="level">
         <short>7</short>
        </void>
        <void property="name">
         <string>ティア・マナリス</string>
        </void>
        <void property="race">
         <byte>4</byte>
        </void>
        <void property="single">
         <boolean>true</boolean>
        </void>
        <void property="weight">
         <float>39.6</float>
        </void>
       </object>
      </void>
      <void index="1"> 
       <object class="xml.ObjectSample"> 
        <void property="age"> 
         <int>293</int> 
        </void> 
        <void property="exp"> 
         <long>7300</long> 
        </void> 
        <void property="gender"> 
         <char>F</char> 
        </void> 
        <void property="height"> 
         <double>151.6</double> 
        </void> 
        <void property="level"> 
         <short>8</short> 
        </void> 
        <void property="name"> 
         <string>エリス</string> 
        </void> 
        <void property="race"> 
         <byte>1</byte> 
        </void> 
        <void property="weight"> 
         <float>38.8</float> 
        </void> 
       </object> 
      </void> 
      <void index="2">
       <object class="xml.ObjectSample">
        <void property="age">
         <int>27</int>
        </void>
        <void property="exp">
         <long>2100</long>
        </void>
        <void property="gender">
         <char>M</char>
        </void>
        <void property="height">
         <double>173.4</double>
        </void>
        <void property="level">
         <short>2</short>
        </void>
        <void property="name">
         <string>デリック・ラプター</string>
        </void>
        <void property="single">
         <boolean>true</boolean>
        </void>
        <void property="weight">
         <float>69.2</float>
        </void>
       </object>
      </void>
     </array>
    </java>
    
    

    読み込むときも、格納先クラスを配列にして、戻り値をそのクラス配列のインスタンスに設定すれば、項目名も判定してしかるべき箇所に格納してくれます。

    サンプルプログラム

    XMLTester.java
    
    package xml;
    
    public class XMLTester {
    
        final static String FILE_NAME = "test.xml";
    
        public static void main( String[] args ) {
    
            XMLStream xmlStream = new XMLStream(FILE_NAME);
            ObjectSample    objSample[] = (ObjectSample[])xmlStream.readXML();
    
            for( int i = 0 ; i < objSample.length ; i ++ ) {
                System.out.println( "Name   = " + objSample[i].getName());
                System.out.println( "Gender = " + objSample[i].getGender());
                System.out.println( "Height = " + objSample[i].getHeight());
                System.out.println( "Weight = " + objSample[i].getWeight());
                System.out.println( "Race   = " + objSample[i].getRace());
                System.out.println( "Level  = " + objSample[i].getLevel());
                System.out.println( "Age    = " + objSample[i].getAge());
                System.out.println( "Exp    = " + objSample[i].getExp());
                System.out.println( "Single = " + objSample[i].getSingle());
                System.out.println( "" );
            }
    
        }
    
    }
    
    

    出力結果

    
    Name   = ティア・マナリス
    Gender = F
    Height = 147.3
    Weight = 39.6
    Race   = 4
    Level  = 7
    Age    = 49
    Exp    = 5400
    Single = true
    
    Name   = エリス
    Gender = F
    Height = 151.6
    Weight = 38.8
    Race   = 1
    Level  = 8
    Age    = 293
    Exp    = 7300
    Single = false
    
    Name   = デリック・ラプター
    Gender = M
    Height = 173.4
    Weight = 69.2
    Race   = 0
    Level  = 2
    Age    = 27
    Exp    = 2100
    Single = true
    
    

    Back「プログラミング・ノウハウ集」に戻る
    Topトップページに戻る