マイペースなプログラミング日記

DTMやプログラミングにお熱なd-kamiがマイペースに書くブログ

AndroidでXPath

Android 2.2からXPathが使えるようになったので使ってみた。使うまでがめんどいけど、XmlPullParserより使いやすいと思う。以下のXMLを対象にXPathを使ってみた。あまり詳しく書かないけど、少しだけ解説を載せたあと、ソースコードを載せる

<memo>
  <contents name="チラシの表">Hoge</text>
  <contents name="チラシの裏">Piyo</text>
</memo>


XPathの例:
memoの1つ下のcontentsを取得する

/memo/contents


memoの1つ下の複数のcontentsの中から属性値が"チラシの表"のノードを取得する

/memo/contents[@name="チラシの表"]


memoの下の複数のcontentsの中から属性値が"チラシの表"の下のテキスト(Hoge)を取得する

/memo/contents[@name="チラシの表"]/text()


Javaで扱う場合:
Hogeを取得する例。XPathのevaluateを使う。最初の引数にXPathの文字列を、次の引数にXPathの基準となるノードを指定する。2つの引数のevaluateはStringを返す

String result = xpath.evaluate("/memo/contents[@name=\"チラシの裏\"]/text()", document);


複数のノードを返す例。XPathのevaluateを使うが、3つ目の引数にXPathConstants.NODESETを指定する。返ってくるのは3つ目の引数次第でObject型として返って来るのでキャストする。今回はNodeListを返してくる

NodeList result = (NodeList)xpath.evaluate("/memo/contents", document, XPathConstants.NODESET);


以下、ソースコード

package test.xpath;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

import java.io.ByteArrayInputStream;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;

public class XPathActivity extends Activity {
    private String xml;
    private TextView resultView;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        resultView = new TextView(this);
        
        initXMLString();
        xpathResult();
        
        setContentView(resultView);
    }
    
    private void initXMLString(){
        xml = "<memo>";
        xml += "<contents name=\"チラシの表\">";
        xml += "Hoge";
        xml += "</contents>";
        xml += "<contents name=\"チラシの裏\">";
        xml += "Piyo";
        xml += "</contents>";
        xml += "</memo>";
    }
    
    private void xpathResult(){
        try{
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dbFactory.newDocumentBuilder();
            Document document = builder.parse(new ByteArrayInputStream(xml.getBytes()));
        
            XPathFactory factory = XPathFactory.newInstance();
            XPath xpath = factory.newXPath();

            String result = xpath.evaluate("/memo/contents[@name=\"チラシの表\"]/text()", document) + "\n";
            result += xpath.evaluate("/memo/contents[@name=\"チラシの裏\"]/text()", document) + "\n";

            //memoの1つしたの全てのcontentsノードを取り出す
            NodeList textList = (NodeList)xpath.evaluate("/memo/contents", document, XPathConstants.NODESET);

            //contentsノードを1つずつ取り出して更にXPathでアクセスする
            //ここではcontentsからの相対パスとなっている
            for(int i = 0; i < textList.getLength(); i++){
                Node node = textList.item(i);

                //name属性を取り出す(属性名の前に@を付ける)
                result += xpath.evaluate("./@name", node) + ": ";
                //contentsの下のテキストを取り出す
                result += xpath.evaluate("./text()", node) + "\n";
            }
    
            resultView.setText(result);
        }catch(Exception exception){
            resultView.setText(exception.getClass().getName() + ": " + exception.getMessage());
        }
    }
}