前回までで考えた、javax.xml.namespace.NamespaceContext の実装をサポートする抽象クラスは、結局、次のようになります(一覧):
import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.xml.namespace.NamespaceContext; import static javax.xml.XMLConstants.*; /** @author waman */ public abstract class AbstractNamespaceContext implements NamespaceContext{ private static final List<String> XML = Collections.singletonList(XML_NS_PREFIX); private static final List<String> XMLNS = Collections.singletonList(XMLNS_ATTRIBUTE); /** 親ノードの NamespaceContext を返します。 */ protected abstract NamespaceContext getParentContext(); /** * 第0引数の文字列で指定される接頭辞に対応する名前空間 URI を返します。 * 祖先要素には遡りません。 * 該当する名前空間 URI が見つからなかった場合、null を返します。 */ protected abstract String getNamespaceURIonCurrentNode(String prefix); /** * 第0引数で指定される名前空間 URI に対応する接頭辞のリストを返します。 * 祖先要素には遡りません。 * 該当する接頭辞が見つからなかった場合は空の List を返します * (以前は null を返すとしてましたが間違いです)。 */ protected abstract List<String> getPrefixesOnCurrentNode(String uri); public String getNamespaceURI(String prefix) { if(prefix == null) throw new IllegalArgumentException("Prefix can't be null"); if(XML_NS_PREFIX.equals(prefix)) return XML_NS_URI; if(XMLNS_ATTRIBUTE.equals(prefix)) return XMLNS_ATTRIBUTE_NS_URI; // prefix bound on the current node String uri = getNamespaceURIonCurrentNode(prefix); if(uri != null) return uri; NamespaceContext parent = getParentContext(); if(parent != null) // prefix bound on a parent node return parent.getNamespaceURI(prefix); // unbound prefix return NULL_NS_URI; } public String getPrefix(String uri) { validateURI(uri); 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); // unbound namespace uri if(prefixes.size() == 0) return null; for(String prefix: prefixes){ // default namespace uri if(prefix.length() == 0) return prefix; } // bound namespace uri return prefixes.get(0); } public Iterator<String> getPrefixes(String uri) { validateURI(uri); if(XML_NS_URI.equals(uri)) return XML.iterator(); if(XMLNS_ATTRIBUTE.equals(uri)) return XMLNS.iterator(); return getPrefixList(uri).iterator(); } private List<String> getPrefixList(String uri){ List<String> parentPrefixes = getParentPrefixList(uri); List<String> prefixes = new LinkedList<String>(); for(String prefix: parentPrefixes){ String u = getNamespaceURIonCurrentNode(prefix); if(u == null || u.equals(uri)) prefixes.add(prefix); } prefixes.addAll(getPrefixesOnCurrentNode(uri)); return prefixes; } private void validateURI(String uri){ if(uri == null || NULL_NS_URI.equals(uri)) throw new IllegalArgumentException("URI can't be null or empty String"); } private List<String> getParentPrefixList(String uri){ List<String> prefixes = new LinkedList<String>(); NamespaceContext parent = getParentContext(); if(parent != null){ Iterator<?> ite = parent.getPrefixes(uri); while(ite.hasNext()) prefixes.add((String)ite.next()); } return prefixes; } }
空白文字列の名前空間 URI の扱いを、以前の記事に載せたメソッドの実装から前回で見た挙動へと変更しています。 また、名前空間 URI や接頭辞の定数を javax.xml.XMLConstants のフィールドで置き換えています。