Java5 XPath

J2SE1.5.0_05で試しています。

以下のようなXML文書を:

<?xml version="1.0"?>
<plugin xmlns="http://d.hatena.ne.jp/bellbind/plugin/1.0"
  id="foo.bar">
  <extension-point id="foo.bar.Ext" class="foo.FooExt" version="1"/>
  <extension-point id="foo.bar.Ext2" class="foo.FooExt2" version="2"/>
</plugin>

XPathを使って解析するJavaプログラムを書いてみます:

import java.io.*;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
import org.w3c.dom.*;
import org.xml.sax.*;

public class XPathReading {
    public static void main(String[] args)
    throws IOException, ParserConfigurationException, SAXException, XPathExpressionException {
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document document1 = builder.parse(new File("plugin.xml"));
        
        XPath xpath = XPathFactory.newInstance().newXPath();
        
        String pluginId = xpath.evaluate("/plugin/@id", document1); // result type: String
        System.out.println(pluginId);
        
        // pre-compile
        XPathExpression extensionPointPath = xpath.compile("/plugin/extension-point");
        // NodeList type
        NodeList extensionPoints = (NodeList) extensionPointPath.evaluate(document1, XPathConstants.NODESET);
        
        for (int i = 0; i < extensionPoints.getLength(); i++) {
            Element extensionPoint = (Element) extensionPoints.item(i);
            System.out.println(extensionPoint.getAttribute("id")); // dom api
            
            System.out.println(xpath.evaluate("@class", extensionPoint)); // xpath api
            
            Double version = (Double) xpath.evaluate("@version", extensionPoint, XPathConstants.NUMBER);
            System.out.println(version.intValue());
        }
    }
}

さすがJavaなので長い。結果:

$ java -classpath . XPathReading
foo.bar
foo.bar.Ext
foo.FooExt
1
foo.bar.Ext2
foo.FooExt2
2

XPathエンジンの取得は、デフォルトのエンジンを使うのであれば以下のとおり。

XPath xpath = XPathFactory.newInstance().newXPath();

XPathFactoryファクトリーオブジェクトはエンジンプログラムのタイプごとに切り替えられます。XPathエンジンは、同じ名前空間エリアス、変数参照や関数定義(ユーザー定義のものが設定できる)を使う範囲で使いまわせます。

XPath評価はevaluateメソッドです。戻り値を指定しない場合は文字列、指定した場合はそれにあった型でかえります。型は自分で適切なものを選択しなくてはいけません。

  • たとえばElementを返すXPathで戻り値を指定しないと、空文字列になります。
  • 複数のノードを返すものはNodeListにしないかぎり、はじめの一つだけが返ります。
String value = xpath.evaluate(xpathExp, node);
String value = (String) xpath.evaluate(xpathExp, node, XPathConstants.STRING);
boolean value = (Boolean) xpath.evaluate(xpathExp, node, XPathConstants.BOOLEAN);
Double value = (Double) xpath.evaluate(xpathExp, node, XPathConstants.NUMBER);
Node value = (Node) xpath.evaluate(xpathExp, node, XPathConstants.NODE);
NodeList value = (NodeList) xpath.evaluate(xpathExp, node, XPathConstants.NODESET);

第二引数はDocumentやElementなどが渡せます。NodeListやFileなどは直接渡せませんでした。

XPathExpressionはプリコンパイル形式で、固定のXPath式を使いまわすときに処理速度があがるでしょう。メソッドはevaluateのみで、引数はXPathのevaluateの第一引数がなくなっただけです。