本家「@IT」にはない内容をエンジニアライフで技術紹介するコラム。広く議論する場になることを目指します。

第057回_一般実体テーブル作成処理の実装1

»

5回にわたってW3Cの勧告を読み、仕様を整理しました。
仕様の整理に従って、
 1.実体宣言から一般実体テーブルを作成する処理
 2.実体宣言からパラメータ実体テーブルを作成する処理
 3.内容(Content)内の参照の展開処理
を実装していきます。

まずは、一般実体から見ていきます。

実体宣言から一般実体テーブルの作成処理のクラス群

関連するクラスは次のようにします。


クラス名説明
GeneralEntityData 一般実体データの抽象クラス
AbstractInternalParsedEntityData内部・解析対象 ・一般実体データの抽象クラス
InternalParsedEntityData 内部・解析対象 ・一般実体 を表すデータクラス
PredefinedEntityData 内部・解析対象 ・一般実体の内定義済み実体 を表すデータクラス
ExternalParsedEntityData 外部・解析対象 ・一般実体 を表すデータクラス
ExternalUnparsedEntityData 外部・解析対象外・一般実体 を表すデータクラス
GeTable 一般実体テーブル(Mapをラッパーするクラス)
MakingGeTableVisitor 一般実体テーブルを作成するVisitor

実装

GeneralEntityDataの実装
GeneralEntityDataクラスは一般実体を表す抽象クラスです。

public abstract class GeneralEntityData
{
    private String m_name;
    
    //パラメータ実体の中で宣言された実体宣言かどうかのフラグ
    //(整形式のチェックのために設定する)
    private boolean m_inParametorDeclaration;

    //外部サブセットの中で宣言された実体宣言かどうかのフラグ
    //(整形式のチェックのために設定する)
    private boolean m_inExtSubsetDeclaration;
    
    public GeneralEntityData()
    {
        m_name="";
        m_inParametorDeclaration = false;
        m_inExtSubsetDeclaration = false;
    }
    
    public void setName(String name)
    {
        m_name = name;
    }
    
    public String getName()
    {
        return m_name;
    }
    
    public void setParametorDeclaration(boolean b)
    {
        m_inParametorDeclaration = b;
    }

    public void setExtSubsetDeclaration(boolean b)
    {
        m_inExtSubsetDeclaration = b;
    }

    //外部マークアップ宣言かどうかを判定する
    public boolean isExternalMarkupDeclaration()
    {
        //DeclSep内で宣言した実体宣言の場合
        //または、
        //外部サブセット内で宣言した実体宣言の場合
        //外部マークアップ宣言として、trueを返す
        return (m_inParametorDeclaration || m_inExtSubsetDeclaration);
    }

    //同名のデータで2つ目以降のデータがきた場合に呼び出す
    public void marge(GeneralEntityData ged)
    {
        //TODO オプションが有効なら警告を出しても良い
    }
    
    //定義済み実体に対して同名の一般実体を取得するためのメソッド
    public InternalParsedEntityData getInstanceIfInternalParsedEntity()
    {
        return null;
    }
}
各フィールドの解説をします。
m_name : 一般実体名の値
m_inParametorDeclaration : DeclSep内の宣言を表す。trueはDeclSep内の宣言
m_inExtSubsetDeclaration : 外部サブセットの宣言を表す。trueは外部サブセット内の宣言

既に説明した整形式性制約をチェックする場合に、外部マークアップ宣言かを判定
する必要があるため、DeclSepと外部サブセットの中で宣言したものかの情報を持ちます。

margeメソッドは、同名のkeyに対して重複して宣言した場合の処理になります。
オプションによって警告を出す処理が必要ですが、例外やエラーに対するクラスがないので何もしていません。

getInstanceIfInternalParsedEntityメソッドは、InternalParsedEntityクラス以外ではnullを返すメソッドです。
基底クラスではnullを返しておきます。

AbstractInternalParsedEntityDataの実装
AbstractInternalParsedEntityDataは内部・解析対象・一般実体を表す抽象データクラスです。
抽象クラスを用意する理由は、定義済みのモノと定義済みでないモノの2種類があるからです。

public abstract class AbstractInternalParsedEntityData
extends GeneralEntityData
{
    //置換テキスト
    protected String m_replacementText;
    
    public AbstractInternalParsedEntityData()
    {
        m_replacementText = "";
    }
    
    public String toString()
    {
        return m_replacementText;
    }
    
    @Override
    public boolean canReferenceAtEntityValue(){return true;}
}

InternalParsedEntityDataの実装
InternalParsedEntityDataは内部・解析対象・一般実体を表すデータクラスです。

public class InternalParsedEntityData
extends AbstractInternalParsedEntityData
{
    public InternalParsedEntityData()
    {
    }
    
    public void setText(String value)
    {
        m_replacementText = value;
    }
    
    public InternalParsedEntityData getInternalParsedEntity()
    {
        return this;
    }
}

PredefinedEntityDataの実装
PredefinedEntityDataは内部・解析対象・一般実体の内、定義済み実体 を表す抽象データクラスです。
定義済み実体は、次の機能を持ちます。
フィールド
m_baseList : 置換テキストとして指定できる文字列の候補リスト
m_nomalDeclared: 個別に定義した場合の内部・解析対象・一般実体のデータ(2つ目以降はマージするので1つだけ持つ)

メソッド
setList: 候補リストを設定する
marge : 登録済みデータが定義済み実体のマージ処理(一般実体のマージ処理をせずに定義済み実体はこちらを実行する)
 1.内部・解析対象・一般実体データが未だ無い場合
 1-1.登録側のデータが内部・解析対象・一般実体でない場合
 1-1-1.エラーとする
 1-2.登録側のデータが内部・解析対象・一般実体の場合
 1-2-1.内部・解析対象・一般実体データとして保存する
 1-2-2.候補リストの文字列の場合
 1-2-2-1.置換文字列に設定する
 1-2-3.候補リストの文字列でない場合
 1-2-3-1.エラーとする
 2.内部・解析対象・一般実体データが既に有る場合
 2-1.内部・解析対象・一般実体データにマージする(定義済み実体でないマージ処理へ)

public class PredefinedEntityData
extends AbstractInternalParsedEntityData
{
    //置換テキストの候補
    private ArrayList<String> m_baseList;
    
    //個別に定義した場合のデータ
    private InternalParsedEntityData m_normalDeclared;
    
    public PredefinedEntityData()
    {
        m_baseList = new ArrayList<String>();
        m_normalDeclared = null;
    }
    
    public void setList(ArrayList<String> list)
    {
        m_baseList = list;
        
        //基本は0番目の要素を置換テキストとする
        m_replacementText = m_baseList.get(0);
    }

    //同名のデータで2つ目以降のデータがきた場合に呼び出す
    @Override
    public void marge(GeneralEntityData ged)
    {
        //定義済み実体だけで一般実体宣言はない場合
        if (m_normalDeclared == null)
        {
            InternalParsedEntityData t = ged.getInternalParsedEntity();
            
            //登録データが内部・解析対象一般実体でない場合
            if (t == null)
            {
                //TODO エラー
            }
            //登録データが内部・解析対象一般実体の場合
            else
            {
                //候補リストにあるか確認する
                String txt = t.toString();
                boolean hasTxt = m_baseList.contains(txt);
                
                //候補リストにある場合
                if (hasTxt)
                {
                    m_replacementText = txt;
                }
                //候補リストにない場合
                else
                {
                    //TODO エラー
                }
                
                m_normalDeclared = t;
            }
        }
        //既に内部・解析対象・一般実体宣言がある場合
        else
        {
            m_normalDeclared.marge(ged);
        }
    }

}

ExternalParsedEntityDataの実装
ExternalParsedEntityDataは外部・解析対象・一般実体 を表すデータクラスです。

public class ExternalParsedEntityData
extends GeneralEntityData
{
    //システム識別子のリテラル
    private String m_systemLiteral;
    //公開識別子のリテラル
    private String m_pubidLiteral;
    
    public ExternalParsedEntityData()
    {
        super();
        
        m_systemLiteral = "";
        m_pubidLiteral  = "";
    }
    
    public void setSystemLiteral(String system)
    {
        m_systemLiteral = system;
    }

    public void setPubidLiteral(String pubid)
    {
        m_pubidLiteral = pubid;
    }
    
    public String getSystemLiteral()
    {
        return m_systemLiteral;
    }

    public String getPubidLiteral()
    {
        return m_pubidLiteral;
    }
}

ExternalUnparsedEntityDataの実装
ExternalUnparsedEntityDataは外部・解析対象外・一般実体を表すデータクラスです。
ただし、記法宣言との関連部分はまだ検討していないため、作成しません。

public class ExternalUnparsedEntityData extends GeneralEntityData
{
    private String m_nDataName;
    private String m_systemLiteral;
    private String m_pubidLiteral;
    
    public ExternalUnparsedEntityData()
    {
        super();
        
        m_nDataName = "";
        m_systemLiteral = "";
        m_pubidLiteral  = "";
    }
    
    public void setNDataName(String name)
    {
        m_nDataName = name;
    }
    
    public void setSystemLiteral(String system)
    {
        m_systemLiteral = system;
    }

    public void setPubidLiteral(String pubid)
    {
        m_pubidLiteral = pubid;
    }
}

GeTableの実装
GeTableは一般実体テーブル(Mapをラッパーするクラス)です。
テーブルは全体で一つなのでシングルトンパターンで作成します。

・初期化時
 直接テーブルに定義済み実体を登録する

・構文解析(Visitor)
 1.一般実体宣言から実体データを作成する
 2.実体データを実体テーブルに登録する

・実体テーブルの登録処理
 1.一般実体名(key)を取得する
 2.テーブルをkeyで検索し、登録済みデータを取得する
 3.登録済みデータが無い場合
 3-1.一般実体を登録する
 4.登録済みデータが有る場合
 4-1.登録済みのデータに合わせて、マージ処理をする


public class GeTable
{
    private final static GeTable m_instance = new GeTable();
    private Map<String,GeneralEntityData> m_map;
    
    //パラメータ実体の内容を解析しているセクションの間だけtrue
    //整形式制約のチェックのための情報
    private boolean m_ParametorEntityParseSection;

    //外部サブセットを解析しているセクションの間だけtrue
    //整形式制約のチェックのための情報
    private boolean m_ExtSubsetParseSection;
    
    private GeTable()
    {
        m_map = new HashMap<String,GeneralEntityData>();
        
        m_ParametorEntityParseSection = false;
        m_ExtSubsetParseSection = false;

        //定義済み実体を設定する
        // lt     "&#60;"
        // gt     ">"      または&#62;
        // amp    "&#38;"
        // apos   "'"      または&#39;
        // quot   "\""     または&#34;
        {
            ArrayList<String> list = new ArrayList<String>();
            list.add("&#60;");
            this.setPredefinedData("lt"  , list);
        }
        
        {
            ArrayList<String> list = new ArrayList<String>();
            list.add(">");
            list.add("&#62;");
            this.setPredefinedData("gt"  , list);
        }

        {
            ArrayList<String> list = new ArrayList<String>();
            list.add("&#38;");
            this.setPredefinedData("amp" , list);
        }

        {
            ArrayList<String> list = new ArrayList<String>();
            list.add("'");
            list.add("&#39;");
            this.setPredefinedData("apos", list);
        }

        {
            ArrayList<String> list = new ArrayList<String>();
            list.add("\"");
            list.add("&#34;");
            this.setPredefinedData("quot", list);
        }
    }
    
    public static GeTable getInstance()
    {
        return m_instance;
    }
    
    public void notifyParametorEntityParseSectionStart()
    {m_ParametorEntityParseSection = true;}

    public void notifyParametorEntityParseSectionEnd()
    {m_ParametorEntityParseSection = false;}
    
    public void notifyExtSubsetParseSectionStart()
    {m_ExtSubsetParseSection= true;}
    
    public void notifyExtSubsetParseSectionEnd()
    {m_ExtSubsetParseSection= false;}
    
    public void setData(GeneralEntityData ged)
    {
        String name = ged.getName();
        ged.setParametorDeclaration(m_ParametorEntityParseSection);
        ged.setExtSubsetDeclaration(m_ExtSubsetParseSection);
        
        //(既に登録してあるかもしれないので)
        //指定のnameでマップからデータを取り出す
        GeneralEntityData ged2 = m_map.get(name);
        
        //未だ同名の一般実体が登録してない場合
        if (ged2 == null)
        {
            //一般実体を登録する
            m_map.put(name, ged);
            System.out.println("Entity "+name+":"+ged);
        }
        //既に同名の一般実体が登録してある場合
        else
        {
            //マージする
            //  定義済み実体以外の場合はエラーとなる
            //  定義済み実体の場合はエラーにするかは
            //  定義済み実体側の状態で判断する
            ged2.marge(ged);
        }
    }
    
    public GeneralEntityData getData(String name)
    {
        return m_map.get(name);
    }
    
    //定義済み実体を登録する
    private void setPredefinedData(String name, ArrayList<String> list)
    {
        PredefinedEntityData ged = new PredefinedEntityData();
        ged.setName(name);
        ged.setList(list);
        m_map.put(name, ged);
    }
}

長くなったのでMakingGeTableVisitorの説明は次回にします。
Comment(0)

コメント

コメントを投稿する