倭マン's BLOG

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

NamespaceContext の実装を考える (4) : メソッド getPrefix()

今回は NamespaceContext#getPrefix() メソッド(一覧)。

NamespaceContext#getPrefix(String) の返り値


Java SE 6 の API ドキュメントを見ると、返り値は以下のように定義されています:

引数の名前空間 URI 返り値
http://www.w3.org/XML/1998/namespace xml
http://www.w3.org/2000/xmlns/ xmlns
null IllegalArgumentException が投げられる
デフォルト名前空間 空文字列
対応する名前空間宣言がある場合(デフォルト名前空間以外) 対応する接頭辞(複数ある場合の返り値は実装に依存)
対応する名前空間宣言がない場合 null

少し注意が必要なのは、指定された名前空間 URIデフォルト名前空間になっている場合でしょうか。 このとき、同じ URI に他の接頭辞が関連づけられていても、きちんと空文字列を返す必要があります。

例えば、以下のような XML 文書があった時

<a xmlns="xyz">
  <b xmlns:p="xyz"/>
</a>

要素 <b> の NamespaceContext オブジェクト context_b に対して、メソッド呼び出し

context_b.getPrefix("xyz");

空文字列を返さなければいけません("p" を返してはいけません)。

接頭辞の解決手順


接頭辞の解決手順は以下の通り:

  1. 引数の名前空間 URI が null, "http://www.w3.org/XML/1998/namespace", "http://www.w3.org/2000/xmlns/" の場合は、対応する接頭辞を返す(もしくは例外を投げる)
  2. 指定された名前空間 URI に対応する接頭辞のリストを取得する(前回作成したメソッド AbstractNamespaceContext#getPrefixList(String) を用いる)
  3. リストが空なら、null を返す
  4. リストが空文字列を含むなら、それを返す(デフォルト名前空間
  5. リストに含まれる要素を1つ適当に返す。

実装


実装は概ね以下の通り:

/** @author waman */
public abstract class AbstractNamespaceContext implements NamespaceContext{

    ...

    public String getPrefix(String uri) {
        if(uri == null)
            throw new IllegalArgumentException("Namespace URI cannot be null !");
        if(XML_NS_URI.equals(uri))
            return XML_NS_PREFIX;
        if(XMLNS_ATTRIBUTE_NS_URI.equals(uri))
            return XMLNS_ATTRIBUTE;
        
        List<String> prefixes = getPrefixList(uri);
        
        // 対応する接頭辞がない場合
        if(prefixes.size() == 0)
            return null;
        
        for(String prefix: prefixes){
            // デフォルト名前空間の場合
            if(prefix.length() == 0)
                return prefix;
        }
        
        // 対応する接頭辞がない場合(デフォルト名前空間以外)
        return prefixes.get(0);
    }

    private List<String> getPrefixList(String uri){
        ...
    }
}