名前空間付き XML
XML の名前空間 (Namespace) を使用することでひとつの XML ドキュメント内に複数のスキーマを混在させることができる。詳細な説明は省略するが、たとえばこれをうまく使うと一つの設定ファイルにさまざまなチーム固有のスキーマを混在させたり、プラグイン的に動作するモジュールが任意のドキュメント内で自分の処理対象の見つけ出し加工するような使い方ができる。
ただし Java ではデフォルトでオフになっているため使い始めで少々躓くかもしれない。
DOM
Java で使用する XML はデフォルトで名前空間がオフになっているので注意が必要 (過去との互換性のためらしい)。getElementsByTagNameNS()
などを使用して特定の名前空間を持つ要素を検索する場合には、そのドキュメントが setNamespaceAware(true)
としたファクトリから構築されていなければならない。
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); Document doc = factory.newDocumentBuilder().parse(file); NodeList nl = doc.getElementsByTagName("http://lab.moyo.biz/ns/foo", "foo");
たとえば上記のように名前空間 http://lab.moyo.biz/ns/foo
を持つローカル名 foo
の要素を検索した場合、下記のドキュメントに対して <x:foo value="mynamespace" />
の要素のみが一致する。
<?xml version="1.0"?> <mydocument xmlns:x="http://lab.moyo.biz/ns/foo" xmlns:y="http://www.mars.dti.ne.jp/ns/bar" > <x:foo value="mynamespace" /> <foo value="othernamespace" /> <y:foo value="othernamespace" /> </mydocument>
XPath
名前空間の付けられている XML ドキュメントに対して XPath でノードを検索する場合も、デフォルトでは名前空間を持たないノードのみしか検索対象にしていないため注意が必要。しかも DOM の場合はフラグひとつ設定するだけで済んだのだが、XPath の場合はプレフィクスと名前空間をマップするクラスを作成した上でプレフィクス付きで XPath を指定しなければならない。
XPath xpath = XPathFactory.newInstance().newXPath(); xpath.setNamespaceContext(new NamespaceContext(){ @Override public String getNamespaceURI(String prefix) { if(prefix.equals("myprefix")){ return "http://lab.moyo.biz/ns/foo"; } if(prefix.equals(XMLConstants.XML_NS_PREFIX)){ return XMLConstants.XML_NS_URI; } return XMLConstants.NULL_NS_URI; } @Override public String getPrefix(String namespaceURI) { if(namespaceURI.equals(uri)){ return prefix; } if(namespaceURI.equals(XMLConstants.XML_NS_URI)){ return XMLConstants.XML_NS_PREFIX; } return XMLConstants.DEFAULT_NS_PREFIX; } @Override public Iterator<String> getPrefixes(String namespaceURI) { // 略… } }); NodeList nl = (NodeList)xpath.evaluate( "/mydocument/myprefix:foo", doc, XPathConstants.NODESET);
XPath 側では名前空間 URI さえ一致していればドキュメント側のプレフィクスと一致させる必要はない。
わざわざユーザ側に実装させなくてもプレフィクスと URI をマッピングする実装済みユーティリティクラスくらい用意してくれていればかなりの手間が省けるはずなのだが。このトントンチキは JCP の仕業なのか W3C 仕業なのか。どちらもやりそうだから困ったものだ。