XPathで名前空間URIを使う
XML Schemaがあるシンプルな構造のXMLデータは、JAXB(id:sunflat:20080430:p1)を使って簡単に読み書きできるけど、XML Schemaが無い場合や複雑に入り組んだXMLデータの場合は、XPathを使うと便利そう。
だた、XPathで、名前空間(namespace URI)のついた要素を検索するのが結構面倒っぽい。NamespaceContextインタフェースを実装したクラスを作れば良いみたいなんだけど。
とりあえず、NamespaceContextインタフェースを実装した以下のようなクラスを作って、
import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; public class SimpleNamespaceContext implements NamespaceContext { private HashMap<String,String> prefixToUri=new HashMap<String,String>(); private HashMap<String,String> UriToPrefix=new HashMap<String,String>(); public void addMapping(String prefix, String uri) { prefixToUri.put(prefix,uri); UriToPrefix.put(uri,prefix); } public SimpleNamespaceContext() { addMapping(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI); addMapping(XMLConstants.XMLNS_ATTRIBUTE, XMLConstants.XMLNS_ATTRIBUTE_NS_URI); } public String getNamespaceURI(String prefix) { if (prefix==null) throw new IllegalArgumentException(); String result=prefixToUri.get(prefix); return result!=null? result : XMLConstants.NULL_NS_URI; } public String getPrefix(String namespaceURI) { if (namespaceURI==null) throw new IllegalArgumentException(); String result=UriToPrefix.get(namespaceURI); return result!=null? result : null; } @SuppressWarnings("unchecked") public Iterator getPrefixes(String namespaceURI) { String prefix=getPrefix(namespaceURI); ArrayList<String> al=new ArrayList<String>(); if (prefix!=null) al.add(prefix); return al.iterator(); } }
以下のようにすれば、"prefix1:local_name"の形で、名前空間のついた要素名を使うことが出来た。
XPath xpath = XPathFactory.newInstance().newXPath(); SimpleNamespaceContext nsc=new SimpleNamespaceContext(); nsc.addMapping("prefix1","http://名前空間URI"); xpath.setNamespaceContext(nsc); xpath.evaluate("//prefix1:local_name", xml_doc, XPathConstants.STRING);