Sunflat のブログ

ソフトウェア開発についての話題が多いかも

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);