Android 向け SAX パーサ用エンティティクラスの設計

XML を解析してデータを取得する際、外部に渡せる形、あるいは内部で扱いやすい形でデータを受け取るためのオブジェクト定義が必要です。このセクションでは、Android 環境で動作する SAX パーサーから得られる情報を保持するためのデータ構造を実装します。それぞれのクラスは Parcelable インターフェースを実装しており、コンポーネント間でのデータ転送が容易になります。

SchoolInfo クラス(学校情報)

最上位のデータ構造として SchoolInfo を定義します。このクラスには複数の専門コース(Major)を管理するリストフィールドが含まれています。XML の School タグに対応し、リストの追加および取得メソッドを実装しています。また、パケット送信に必要なパーセル処理も記述されています。

package tech.example.saxmodel;

import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;

public class SchoolInfo implements Parcelable {
    public static final String NODE_NAME = "School";
    public String displayName;
    public String institutionCode;
    public List<MajorInfo> departments;

    public static final Parcelable.Creator<SchoolInfo> CREATOR = 
            new Parcelable.Creator<SchoolInfo>(){
                @Override
                public SchoolInfo createFromParcel(Parcel in) {
                    return new SchoolInfo(in);
                }

                @Override
                public SchoolInfo[] newArray(int size) {
                    return new SchoolInfo[size];
                }
            };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.displayName);
        dest.writeString(this.institutionCode);
        dest.writeTypedList(this.departments);
    }

    protected SchoolInfo(Parcel in) {
        this.displayName = in.readString();
        this.institutionCode = in.readString();
        if (in.readByte() != null) { // Check read status if list exists
             this.departments = in.createTypedList(MajorInfo.CREATOR);
        } else {
             this.departments = new ArrayList<>();
        }
    }

    public SchoolInfo(String name, String code) {
        this.displayName = name;
        this.institutionCode = code;
        this.departments = new ArrayList<>();
    }

    public void appendDepartment(MajorInfo dept) {
        this.departments.add(dept);
    }

    public List<MajorInfo> getDepartments() {
        return this.departments;
    }

    @Override
    public String toString() {
        return getNameOrDefault();
    }

    private String getNameOrDefault() {
        if(this.displayName == null) {
            return "(未設定)";
        }
        return this.displayName;
    }
}

MajorInfo クラス(学科情報)

次レベルの構造体です。学校内の各専攻を表し、さらにその下に授業グループ(ClassGroup)のリストを持ちます。同様に Parcelable をサポートし、階層構造を正しくシリアライズできるように実装されます。

package tech.example.saxmodel;

import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;

public class MajorInfo implements Parcelable {
    public static final String NODE_NAME = "Major";
    public String subjectName;
    public String departmentCode;
    public List<ClassGroup> groupClasses;

    public static final Parcelable.Creator<MajorInfo> CREATOR = 
            new Parcelable.Creator<MajorInfo>(){
                @Override
                public MajorInfo createFromParcel(Parcel in) {
                    return new MajorInfo(in);
                }

                @Override
                public MajorInfo[] newArray(int size) {
                    return new MajorInfo[size];
                }
            };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.subjectName);
        dest.writeString(this.departmentCode);
        dest.writeTypedList(this.groupClasses);
    }

    protected MajorInfo(Parcel in) {
        this.subjectName = in.readString();
        this.departmentCode = in.readString();
        if (in.readByte() != null) {
            this.groupClasses = in.createTypedList(ClassGroup.CREATOR);
        } else {
            this.groupClasses = new ArrayList<>();
        }
    }

    public MajorInfo(String name, String code) {
        this.subjectName = name;
        this.departmentCode = code;
        this.groupClasses = new ArrayList<>();
    }

    public String getCode() { 
        return (this.departmentCode); 
    }

    public void addClassGroup(ClassGroup c) {
        this.groupClasses.add(c);
    }

    public List<ClassGroup> getClassGroups() {
        return this.groupClasses;
    }    
    
    @Override
    public String toString() {
        return getNameOrDefault();
    }

    private String getNameOrDefault() {
        if(this.subjectName == null) {
            return "(未設定)";
        }
        return this.subjectName;
    }
}

ClassGroup クラス(講義単位)

データ階層の終端となるクラスです。リストを持つ必要はありませんが、親クラス同様、 parcels 間の転送やログ出力のために ParcelabletoString() のオーバーライドが必要です。

package tech.example.saxmodel;

import android.os.Parcel;
import android.os.Parcelable;

public class ClassGroup implements Parcelable {
    public static final String NODE_NAME = "Class";
    
    public String className;
    public String classIdentifier;

    public static final Parcelable.Creator<ClassGroup> CREATOR = 
            new Parcelable.Creator<ClassGroup>(){
                @Override
                public ClassGroup createFromParcel(Parcel in) {
                    return new ClassGroup(in);
                }

                @Override
                public ClassGroup[] newArray(int size) {
                    return new ClassGroup[size];
                }
            };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.className);
        dest.writeString(this.classIdentifier);
    }

    protected ClassGroup(Parcel in){
        this.className = in.readString();
        this.classIdentifier = in.readString();
    }
    
    public ClassGroup(final String name, final String code){
        this.className = name;
        this.classIdentifier = code;
    }
    
    @Override
    public String toString() {
        return getNameOrDefault();
    }	
	
    private String getNameOrDefault() {
        if(this.className == null) {
            return "(未設定)";
        }
        return this.className;
    }
}

これらの実装において、静的な NODE_NAME フィールドは、元の XML ファイル内の要素名と照合するために使用されます。displayName および institutionCode (またはこれらに相当するフィールド)は、それぞれ XML ノードの属性またはテキスト内容と紐付けられます。オブジェクトの状態を確認するためには、必ず toString() メソッドをオーバーライドしてください。これを怠ると、参照アドレスの文字列が表示されたり、不正なデフォルト値が返ったりする可能性があります。

タグ: Android Java xml-parsing SAX parcelable

6月19日 22:04 投稿