JavaとXPathの完全ガイド!15のサンプルコードでマスター

JavaとXPathを組み合わせたコーディングのイメージ図 Java

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

このサービスはSSPによる協力の下、運営されています。

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

この記事を読めば、JavaでXPathを使ったコーディングができるようになります。

はじめにJavaとXPathって何か?と思っている人もいるでしょう。

それに答えながら、基本から応用まで、詳細なサンプルコードを通じて具体的な使い方を解説していきます。

データの取得や操作、さらにはその応用例や注意点、カスタマイズ方法まで、幅広く触れます。

●JavaとXPathの基礎知識

○Javaとは

Javaは、1995年にサン・マイクロシステムズ(現在はオラクル社が所有)によって開発されたプログラミング言語です。

プラットフォームに依存しない、すなわち「一度書いて、どこでも動かせる」をコンセプトとしています。

WebアプリケーションからAndroidアプリ、ビッグデータ解析など、多岐にわたる場で使用されています。

○XPathとは

XPath(XML Path Language)は、XML文書内の要素や属性にアクセスするための言語です。

簡単に言えば、XMLデータから特定の情報をピンポイントで取得する際に使用されるツールです。

その力を発揮する場面は多く、Webスクレイピングからデータ解析、さらには設定ファイルの読み取りなどでよく使われます。

●JavaでのXPathの使い方

前回はJavaとXPathの基礎について説明しましたが、今回は実際にJavaでXPathを使用する方法について詳しく解説します。

基本的な使い方から始め、次に応用的な使い方を説明します。

それでは、さっそくサンプルコードを見ていきましょう。

○基本的な使い方

JavaでXPathを使用するためにはいくつかのステップが必要です。

まず、XPathFactoryというクラスを使用してXPathオブジェクトを生成します。

その後、XPathオブジェクトを使用してXMLデータに対するクエリを行います。

□サンプルコード1:JavaでのXPathの初期化

JavaでXPathを使うためには初期設定が必要です。

XPathを初期化するJavaのサンプルコードを紹介します。

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

public class XPathInitialization {
    public static void main(String[] args) {
        // XPathFactoryインスタンスの取得
        XPathFactory xPathFactory = XPathFactory.newInstance();

        // XPathインスタンスの生成
        XPath xPath = xPathFactory.newXPath();

        // 以降でxPathを使用してXMLファイルを操作
    }
}

このサンプルコードはXPathFactoryを用いてXPathオブジェクトを生成しています。

XPathオブジェクトが生成されると、このオブジェクトを用いてXML文書を操作できます。

実行後の状態で特に出力はありませんが、この設定が完了すればXPathオブジェクトを使ってXMLファイルを操作する準備が整います。

□サンプルコード2:JavaでのXPathでの要素の取得

続いて、実際にXMLデータから要素を取得する方法を見ていきます。

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
    <book>
        <title lang="ja">Java入門</title>
        <price>3200</price>
    </book>
    <book>
        <title lang="en">Learn Java</title>
        <price>2500</price>
    </book>
</bookstore>

このXMLから日本語の書籍タイトルを取得するJavaコードは次のようになります。

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import java.io.StringReader;

public class ElementRetrieval {
    public static void main(String[] args) {
        String xml = "(上記のXMLデータ)";  // XMLデータをここにコピー

        // XPathの初期設定
        XPathFactory xPathFactory = XPathFactory.newInstance();
        XPath xPath = xPathFactory.newXPath();

        try {
            // 日本語の書籍タイトルを取得
            String expression = "/bookstore/book/title[@lang='ja']";
            NodeList nodeList = (NodeList) xPath.evaluate(expression, new InputSource(new StringReader(xml)), XPathConstants.NODESET);

            for (int i = 0; i < nodeList.getLength(); i++) {
                System.out.println(nodeList.item(i).getTextContent());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

このコードは、XPathの表現を用いて日本語(lang=”ja”)の書籍タイトルを取得しています。

具体的には、XPathのevaluateメソッドを用いています。

このコードを実行すると、出力結果として「Java入門」という文字列が表示されます。

○応用的な使い方

基本的な使い方については理解が深まったと思います。

ここでは、それを応用したXML要素の取得法について紹介します。

□サンプルコード3:属性を利用した要素の取得

XML要素には属性が付与されていることが多く、それを基にデータを取得する場合があります。

下記のJavaコードは、XML内の特定の属性を持つ要素をXPathで取得する例です。

// XPathの初期設定は前回のサンプルコード参照

public class RetrieveByAttribute {
    public static void main(String[] args) {
        String xml = "(上記のXMLデータ)";  // XMLデータは前の例と同じ
        try {
            // XPath式でlang属性が'en'のtitle要素を取得
            String expression = "/bookstore/book/title[@lang='en']";
            NodeList nodeList = (NodeList) xPath.evaluate(expression, new InputSource(new StringReader(xml)), XPathConstants.NODESET);

            // 結果の出力
            for (int i = 0; i < nodeList.getLength(); i++) {
                System.out.println(nodeList.item(i).getTextContent());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

このコードを実行すると、”Learn Java”という文字列が出力されるはずです。

このようにして属性を用いて特定の要素を取得することができます。

□サンプルコード4:条件式を使った要素のフィルタリング

さらに、XPathでは条件式を用いてより複雑な要素のフィルタリングが可能です。

下記のサンプルコードでは、価格が3000以上のbook要素だけを取得しています。

// XPathの初期設定は前回のサンプルコード参照

public class RetrieveByCondition {
    public static void main(String[] args) {
        String xml = "(上記のXMLデータ)";  // XMLデータは前の例と同じ
        try {
            // XPath式で価格が3000以上のbook要素を取得
            String expression = "/bookstore/book[price>=3000]/title";
            NodeList nodeList = (NodeList) xPath.evaluate(expression, new InputSource(new StringReader(xml)), XPathConstants.NODESET);

            // 結果の出力
            for (int i = 0; i < nodeList.getLength(); i++) {
                System.out.println(nodeList.item(i).getTextContent());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

このコードを実行すると、”Java入門”という文字列が出力されます。

このようにして、条件式を用いて特定の要素を効率よく取得することができます。

●JavaとXPathの応用例

基本的な使い方から応用まで解説してきましたが、さらにレベルアップするためにはどうすればよいでしょうか。

ここでは、具体的な応用例について説明します。

○情報取得と解析

JavaとXPathを組み合わせて、XMLデータから情報を抽出し、その上で何らかの解析を行う場面が考えられます。

□サンプルコード5:特定の情報を抽出する

このJavaのサンプルコードは、価格が3000以上の書籍に限定して、タイトルと価格を取得するものです。

// ここでは既にXPathオブジェクトが作成されていると仮定します。
String xml = "<bookstore>..."; // XMLデータは事前に準備
String expression = "/bookstore/book[price>=3000]";
NodeList nodeList = (NodeList) xPath.evaluate(expression, new InputSource(new StringReader(xml)), XPathConstants.NODESET);

// 結果の処理
for (int i = 0; i < nodeList.getLength(); i++) {
    Element bookElement = (Element) nodeList.item(i);
    String title = bookElement.getElementsByTagName("title").item(0).getTextContent();
    String price = bookElement.getElementsByTagName("price").item(0).getTextContent();
    System.out.println("タイトル: " + title + ", 価格: " + price);
}

このコードを実行すると、価格が3000以上の書籍のタイトルと価格がコンソールに表示されます。

このようにXPathを使うことで、XMLデータから特定の条件を満たす要素を効率よく取得できます。

□サンプルコード6:情報を加工して出力する

次のコードでは、取得した書籍の情報(タイトルと価格)を加工して、一定の形式で出力します。

// XPathオブジェクトとXMLデータは前の例と同様
String expression = "/bookstore/book";
NodeList nodeList = (NodeList) xPath.evaluate(expression, new InputSource(new StringReader(xml)), XPathConstants.NODESET);

// 結果の加工と出力
StringBuilder report = new StringBuilder();
for (int i = 0; i < nodeList.getLength(); i++) {
    Element bookElement = (Element) nodeList.item(i);
    String title = bookElement.getElementsByTagName("title").item(0).getTextContent();
    String price = bookElement.getElementsByTagName("price").item(0).getTextContent();
    report.append("タイトル: ").append(title).append(", 価格: ").append(price).append("\n");
}
System.out.println("書籍情報のレポート:\n" + report);

このコードを実行した場合、各書籍のタイトルと価格が改行で区切られて出力されます。

これにより、独自のレポート形式でXMLデータを解析・出力する事例を実装できました。

○操作と変更

情報の取得と解析に続いて、XMLデータの「操作と変更」に焦点を当てます。

ここでは、JavaとXPathを用いてXMLデータをどのように編集するかについて詳しく解説します。

□サンプルコード7:XPathで要素を変更する

JavaとXPathを使って、特定のXML要素のテキスト内容を変更するサンプルコードを見てみましょう。

import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;

// サンプルのXMLデータ
String xml = "<bookstore><book><title>初めてのJava</title><price>2500</price></book></bookstore>";

// XPathとDocumentオブジェクトの初期化
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xml)));
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();

// XPathで要素を特定
String expression = "/bookstore/book/title";
Node node = (Node) xpath.evaluate(expression, doc, XPathConstants.NODE);

// 要素のテキストを変更
node.setTextContent("Javaの極意");

// 変更をXMLに反映
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(writer));
String updatedXml = writer.getBuffer().toString();

// 変更後のXMLを出力
System.out.println(updatedXml);

このコードはXPathを用いて/bookstore/book/titleというパスのXML要素を見つけ、そのテキスト内容を「Javaの極意」に変更します。

最後に、その変更をXMLデータに反映しています。

このコードを実行すると、元のXMLデータが変更され、新しいタイトル「Javaの極意」が含まれたXMLが出力されます。

□サンプルコード8:JavaとXPathでXMLを操作する

次に、要素の追加と削除も含めてXMLを操作するサンプルコードを見てみましょう。

// 前述のXPathとDocumentオブジェクトの初期化コードは省略

// 新しい要素を作成して追加
Element newElement = doc.createElement("author");
newElement.setTextContent("山田太郎");
XPathExpression expr = xpath.compile("/bookstore/book");
Node targetNode = (Node) expr.evaluate(doc, XPathConstants.NODE);
targetNode.appendChild(newElement);

// 価格要素を削除
String deleteExpression = "/bookstore/book/price";
Node deleteNode = (Node) xpath.evaluate(deleteExpression, doc, XPathConstants.NODE);
deleteNode.getParentNode().removeChild(deleteNode);

// 変更をXMLに反映(前の例と同様のコード)
// ここでは既にTransformerオブジェクトが作成されていると仮定
StringWriter writer2 = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(writer2));
String updatedXml2 = writer2.getBuffer().toString();

// 変更後のXMLを出力
System.out.println(updatedXml2);

このコードでは、XPathを使用して既存の要素を特定し、新しいauthor要素を追加しています。

さらに、price要素を削除しています。

このコードの実行結果として、author要素が追加され、price要素が削除された新しいXMLデータが出力されます。

○高度なテクニック

JavaとXPathを使った高度なテクニックに焦点を当てます。

この部分では、複雑な条件での要素の抽出や大規模なデータ処理について、詳しく解説します。

□サンプルコード9:複雑な条件での要素の抽出

特定の条件に一致する要素を効率よく抽出する方法を紹介します。

たとえば、価格が3000円以上の本のタイトルを取得したい場合などです。

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

// サンプルのXMLデータ
String xml = "<bookstore>" +
             "<book><title>Java入門</title><price>2800</price></book>" +
             "<book><title>Python入門</title><price>3200</price></book>" +
             "<book><title>PHP入門</title><price>1900</price></book>" +
             "</bookstore>";

// Documentオブジェクトを作成
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xml)));

// XPathオブジェクトを作成
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();

// 複雑な条件で要素を抽出
String expression = "/bookstore/book[price >= 3000]/title";
NodeList nodeList = (NodeList) xpath.evaluate(expression, doc, XPathConstants.NODESET);

// 結果を出力
for (int i = 0; i < nodeList.getLength(); i++) {
    System.out.println(nodeList.item(i).getTextContent());
}

このコードでは、XPathの表現/bookstore/book[price >= 3000]/titleを使用して、価格が3000円以上のbook要素のtitleを取得しています。

このコードを実行すると、”Python入門”というタイトルがコンソールに出力されます。

□サンプルコード10:JavaとXPathでの大規模データ処理

XMLデータが大量にある場合、効率的にデータを処理する方法を説明します。

import javax.xml.xpath.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.StringReader;
import org.xml.sax.InputSource;
import java.util.concurrent.*;

// サンプルのXMLデータ(ここでは短い例で説明)
String xml = "<employees>" +
             "<employee><id>1</id><name>田中</name></employee>" +
             "<employee><id>2</id><name>佐藤</name></employee>" +
             // ...(大量のデータ)...
             "</employees>";

// XPathとDocumentオブジェクトの作成
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xml)));
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();

// スレッドプールを作成
ExecutorService executor = Executors.newFixedThreadPool(4);

// 各スレッドで処理
String expression = "/employees/employee";
NodeList nodeList = (NodeList) xpath.evaluate(expression, doc, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
    int finalI = i;
    executor.submit(() -> {
        Node node = nodeList.item(finalI);
        // 何らかの処理(ここでは名前を出力)
        System.out.println(node.getTextContent());
    });
}
executor.shutdown();

このコードでは、大量のemployee要素が含まれるXMLから、各要素を効率的に処理するためにスレッドプールを使用しています。

具体的には、ExecutorServiceを用いて複数のスレッドでデータを処理しています。

このようにして、大量のデータを効率よく処理することが可能です。

このコードを実行すると、各employeeの情報がマルチスレッドで処理され、コンソールにその名前が出力されます。

●JavaとXPathの注意点と対処法

JavaとXPathを活用する際にもいくつかの注意点や障壁が存在します。

ここでは、特殊な文字や記号の扱いについて詳しく解説します。

○特殊な文字や記号の扱い

XMLやXPathでは、特定の文字や記号には注意が必要です。

例えば、アンパサンド(&)や小なり記号(<)がXMLの要素に含まれている場合、正確なクエリができない、もしくはエラーが発生する可能性があります。

□サンプルコード11:特殊文字を含む要素の取得

特殊な文字を含むXML要素からデータを取得するためのJavaコードを見てみましょう。

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

// サンプルXML(特殊文字を含む)
String xml = "<items><item name='Apple &amp; Orange'>Fruit</item></items>";

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new ByteArrayInputStream(xml.getBytes()));

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

// XPathで特殊文字を含む要素を取得
String expression = "/items/item[@name='Apple &amp; Orange']";
NodeList nodeList = (NodeList) xpath.evaluate(expression, doc, XPathConstants.NODESET);

// 結果を出力
System.out.println(nodeList.item(0).getTextContent());

このJavaコードでは、XML内の&amp;といった特殊なエンコードを正確に扱っています。

XPathクエリ内でも&amp;として明示的に記述している点に注意してください。

このコードを実行すると、コンソールに”Fruit”と表示されます。

□サンプルコード12:エスケープ処理の追加

XMLデータ内の特殊文字を自動的にエスケープする方法もあります。

import org.apache.commons.lang3.StringEscapeUtils;

// 特殊文字を含む文字列
String specialStr = "Apple & Orange";

// エスケープ処理
String escapedStr = StringEscapeUtils.escapeXml11(specialStr);

// エスケープ後の文字列を使用してXMLを生成・処理
// ...

このJavaコードでは、Apache Commons LangのStringEscapeUtilsクラスを用いて特殊な文字列をエスケープしています。

このエスケープ処理を行った後でXML文書を生成することで、特殊文字に起因する問題を防ぐことが可能です。

○パフォーマンス関連

JavaとXPathを用いた開発においては、パフォーマンスも大きな要点の一つです。

特に大量のXMLデータを扱う際には、クエリの効率や実行速度が直接アプリケーションの品質に影響を与えます。

ここでは、XPathのクエリを効率よく実行する方法とJavaでのパフォーマンス最適化について詳しく解説します。

□サンプルコード13:効率的なXPathクエリの書き方

XPathクエリが複雑だと処理速度が遅くなる可能性があります。

より効率的なクエリを作成する方法を見てみましょう。

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

// XPathオブジェクトの初期化
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();

// 効率的なXPathクエリ
String efficientExpression = "/items/item[1]";
NodeList efficientNodeList = (NodeList) xpath.evaluate(efficientExpression, doc, XPathConstants.NODESET);

このJavaコードでは、XPathクエリ内で特定の位置(この場合は1番目)の要素だけを取得しています。

全要素をスキャンするよりも高速です。

このコードを実行すると、XML文書内のitemsタグの下にある最初のitem要素が抽出されます。

□サンプルコード14:JavaでのXPathの最適化手法

Java側でも処理速度の最適化が可能です。

たとえば、XPathFactoryのインスタンスは再利用可能なので、一度生成したら何度も使うといいでしょう。

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

// XPathFactoryの再利用
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath1 = xPathfactory.newXPath();
XPath xpath2 = xPathfactory.newXPath();

このコードでは、XPathFactoryのインスタンスを一度生成してから、それを使って複数のXPathオブジェクトを作成しています。

これにより、新しいFactoryを何度も作らなくて済むため、リソースを節約できます。

パフォーマンスを考慮した開発を行う場合、クエリの最適化だけでなく、Javaのコードにおいても改善の余地は多々あります。

XPathFactoryのような重いオブジェクトは再利用する、不必要なオブジェクトは生成しない、など、日頃から意識することで大幅なパフォーマンスアップが期待できます。

●JavaとXPathのカスタマイズ方法

JavaとXPathの組み合わせでは、基本的な使い方や応用例にとどまらず、さまざまなカスタマイズが可能です。

特に、拡張機能や外部ライブラリを使うことで、更に強力なXML操作が手軽にできるようになります。

○拡張機能やライブラリの利用

JavaでXPathを用いる際には、独自の拡張機能を追加したり、外部ライブラリを活用したりすることで、より高度な操作が可能です。

ここでは、その一例として、SaxonというXPath 3.0対応のライブラリを使ってみましょう。

□サンプルコード15:JavaとXPathを強化するライブラリの利用

まずは、Saxonを利用するためにMavenプロジェクトのpom.xmlに依存関係を追加します。

<dependencies>
  <dependency>
    <groupId>net.sf.saxon</groupId>
    <artifactId>Saxon-HE</artifactId>
    <version>9.9.1-7</version>
  </dependency>
</dependencies>

次に、Saxonを使ったJavaコードを見てみましょう。

import net.sf.saxon.s9api.*;

// Saxonを用いたXPathのプロセッサー初期化
Processor processor = new Processor(false);
XPathCompiler compiler = processor.newXPathCompiler();

// XPath式のコンパイル
XPathExecutable executable = compiler.compile("/bookstore/book[price>30]/title");

// XMLソースの指定
DocumentBuilder builder = processor.newDocumentBuilder();
XdmNode doc = builder.build(new File("bookstore.xml"));

// XPathの評価
XPathSelector selector = executable.load();
selector.setContextItem(doc);
XdmValue value = selector.evaluate();

このコードにおいて、XPath 3.0の機能をフルに活用しています。

特にXPathCompilerクラスは、XPath式を事前にコンパイルすることで、複数回の評価においてパフォーマンスを向上させます。

このコードを実行すると、bookstore.xml内で価格が30より高いbook要素のtitleが抽出されます。

まとめ

この記事では、JavaとXPathの連携について網羅的に解説してきました。

基本的な使い方から応用例、注意点、カスタマイズ方法まで、多角的に観察しました。

更なる探求と実践によって、JavaとXPathの可能性を最大限に引き出してください。

これからも新しい知識やスキルを高めて、多様なプロジェクトで活躍するための手助けとなれば幸いです。