前回までは、DOM や dom4j のようにメモリ上に XML ツリーを展開して扱う API のための NamespaceContext 実装を考えていました(一覧)。
今回はそれを利用して、StAX のような API で用いることのできる NamespaceContext 実装を考えてみます。
方針
実装方針としては、java.util.Map を用いて接頭辞と名前空間 URI を登録できるようにします。 ただし純粋に Map を用いた実装はこちらにあるので*1、ベースとなる NamespaceContext が使えるようにしましょう。 これによって、各要素で一から接頭辞と名前空間 URI のペアを登録する必要が無くなります。
実装クラスの名前は MapNamespaceContext とします。
クラス定義とフィールド
まずはクラス定義とフィールドから。
public class MapNamespaceContext extends AbstractNamespaceContext { private final NamespaceContext baseContext; private final Map<String, String> context; }
クラスは 前回までで作成した AbstractNamespaceContext を継承します。 フィールドは、ベースとなる NamespaceContext オブジェクトとそれに付け加える接頭辞、名前空間 URI のマップを保持する java.util.Map オブジェクトが必要となります。
コンストラクタ
ベースとなる NamespaceContext がなくても MapNamespaceContext が使えるように、コンストラクタは以下の2つを定義します:
public MapNamespaceContext() public MapNamespaceContext(NamespaceContext baseContext)
実装には、何もしない NamespaceContext オブジェクト (NULL_CONTEXT) を用います(この NULL_CONTEXT の実装は間違ってます。 正しくは後日。):
public MapNamespaceContext(){ this(NULL_CONTEXT); } public MapNamespaceContext(NamespaceContext baseContext){ this.baseContext = baseContext; this.context = new HashMap<String, String>(); } private static NamespaceContext NULL_CONTEXT = new NamespaceContext(){ public String getNamespaceURI(String prefix) { return null; } public String getPrefix(String namespaceURI) { return null; } public Iterator<String> getPrefixes(String namespaceURI) { return Collections.<String>emptyList().iterator(); } }; }
接頭辞・名前空間 URI を登録するメソッド
次は接頭辞と名前空間 URI の組を登録するメソッドです。 これらは java.util.Map 風に。 登録を取り消すメソッドは定義していません:
public void put(String prefix, String uri){ this.context.put(prefix, uri); } public void putAll(Map<String, String> map){ this.context.putAll(map); }
AbstractNamespaceContext の抽象メソッド
最期は AbstractNamespaceContext に定義されている抽象メソッドの実装です:
@Override protected NamespaceContext getParentContext() { return this.baseContext; } @Override protected String getNamespaceURIonCurrentNode(String prefix) { if(this.context.containsKey(prefix)) return this.context.get(prefix); else return null; // ※当初 NULL_NS_URI にしてましたが間違いです。; } @Override protected List<String> getPrefixesOnCurrentNode(String uri) { List<String> list = new LinkedList<String>(); for(Entry<String, String> entry: this.context.entrySet()){ if(entry.getValue().equals(uri)) list.add(entry.getKey()); } return list; }
コレで完了。
まとめ
全てをまとめると、結局次のようになります:
public class MapNamespaceContext extends AbstractNamespaceContext { private final NamespaceContext baseContext; private final Map<String, String> context; public MapNamespaceContext(){ this(NULL_CONTEXT); } public MapNamespaceContext(NamespaceContext baseContext){ this.baseContext = baseContext; this.context = new HashMap<String, String>(); } public void put(String prefix, String uri){ this.context.put(prefix, uri); } public void putAll(Map<String, String> map){ this.context.putAll(map); } @Override protected NamespaceContext getParentContext() { return this.baseContext; } @Override protected String getNamespaceURIonCurrentNode(String prefix) { if(this.context.containsKey(prefix)) return this.context.get(prefix); else return null; // ※当初 NULL_NS_URI にしてましたが間違いです。; } @Override protected List<String> getPrefixesOnCurrentNode(String uri) { List<String> list = new LinkedList<String>(); for(Entry<String, String> entry: this.context.entrySet()){ if(entry.getValue().equals(uri)) list.add(entry.getKey()); } return list; } private static NamespaceContext NULL_CONTEXT = new NamespaceContext(){ public String getNamespaceURI(String prefix) { return null; } public String getPrefix(String namespaceURI) { return null; } public Iterator<String> getPrefixes(String namespaceURI) { return Collections.<String>emptyList().iterator(); } }; }