倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

改・NamespaceContext の実装を考える (4) : AbstractCompositeNamespaceContext

AbstractCompositeNamespaceContext は、親となる NamespaceContext(例えば親ノードの NamespaceContext)を持ち、それに加えて追加の名前空間宣言があるような場合に使用する NamespaceContext です。 これは以前の記事での AbstractNamespaceContext に対応するものです(一覧)。

親となる NamespaceContext を取得するメソッド


まず、親となる NamespaceContext(例えば親ノードの NamespaceContext)を取得する抽象メソッドを定義しておきましょう:

protected abstract NamespaceContext getParentContext();

以前は、「親がない場合は null を返す」としてましたが、これを変更して、「親がない場合は EmptyNamespaceContext.INSTANCE を返す」とします。

getNamespaceURISimply(String) メソッドの実装


次に AbstractNamespaceContext クラスに定義された抽象メソッド getNamespaceURI(String) メソッドの実装を考えます。 このために、まず新に次の抽象メソッドを定義します:

protected abstract String getNamespaceURILocally(String prefix);

これは以前の記事で「getNamespaceURIonCurrentNode(String)」としていたもので(6文字も短くなりました(笑))、親ノードを使わずに接頭辞から名前空間 URI を取得するメソッドです。 これを用いて getNamespaceURISimply(String) の実装は以下のようになります:

    protected String getNamespaceURISimply(String prefix) {
    
        // prefix bound on the current node
        String uri = getNamespaceURILocally(prefix);
        if(uri != null)
            return uri;

        // prefix bound on a parent node
        return getParentContext().getNamespaceURI(prefix);
    }

getPrefixSetSimply(String) メソッドの実装


getPrefixSetSimply(String) の実装も getPrefixSetSimply(String) と概ね同じです。 親ノードを使わずに名前空間 URI から接頭辞のセットを取得するメソッドを定義します:

protected abstract Set<String> getPrefixSetLocally(String uri);

これを用いた getPrefixSetSimply(String) の実装は下でまとめて載せておきます。

定義された抽象メソッド


新に定義された抽象メソッドは以下の3つです:

    /**
     * 親ノードの NamespaceContext を返します。
     * 親ノードがない場合は EmptyContext.INSTANCE を返します。 
     */
    protected abstract NamespaceContext getParentContext();

    /**
     * 引数の文字列で指定される接頭辞に対応する名前空間 URI を返します。
     * 祖先要素には遡りません。
     * 該当する名前空間 URI が見つからなかった場合、null を返します。
     */
    protected abstract String getNamespaceURILocally(String prefix);

    /**
     * 引数で指定される名前空間 URI に対応する接頭辞を返します。
     * 祖先要素には遡りません。
     * 該当する接頭辞が見つからなかった場合、空の Set を返します。
     */
    protected abstract Set<String> getPrefixesLocally(String uri);

AbstractNamespace クラスの2つの抽象メソッドは新に実装する必要はありません。

Java コード


AbstractCompositeNamespaceContext の具体的な実装は以下のようになります:

import java.util.*;
import javax.xml.namespace.NamespaceContext;

/** @author waman */
public abstract class AbstractCompositeNamespaceContext
        extends AbstractNamespaceContext{

    /**
     * 親ノードの NamespaceContext を返します。
     * 親ノードがない場合は {@link EmptyNamespaceContext#INSTANCE} を返します。 
     */
    protected abstract NamespaceContext getParentContext();

    protected String getNamespaceURISimply(String prefix) {
    
        // prefix bound on the current node
        String uri = getNamespaceURILocally(prefix);
        if(uri != null)
            return uri;

        // prefix bound on a parent node
        return getParentContext().getNamespaceURI(prefix);
    }

    /**
     * 引数の文字列で指定される接頭辞に対応する名前空間 URI を返します。
     * 祖先要素には遡りません。
     * 該当する名前空間 URI が見つからなかった場合、null を返します。
     */
    protected abstract String getNamespaceURILocally(String prefix);

    protected Set<String> getPrefixSetSimply(String uri){
    
        Set<String> prefixes = new HashSet<String>();
        
        Iterator<?> ite = getParentContext().getPrefixes(uri);
        while(ite.hasNext()){
            String prefix = (String)ite.next();
            String u = getNamespaceURILocally(prefix);
            if(u == null || u.equals(uri))
                prefixes.add(prefix);
        }
            
        prefixes.addAll(getPrefixesLocally(uri));
        return prefixes;
    }

    /**
     * 引数で指定される名前空間 URI に対応する接頭辞を返します。
     * 祖先要素には遡りません。
     * 該当する接頭辞が見つからなかった場合、空の Set を返します。
     */
    protected abstract Set<String> getPrefixesLocally(String uri);
}