感謝のプログラミング 10000時間

たどり着いた結果(さき)は、感謝でした。

JavaでXMLの特定の要素の値を取得する。

スポンサーリンク

JavaでXMLファイルを読み込み、特定の要素の値を取り出すサンプルを作ってみた。

インターフェース メソッド 機能
Node Node getFirstChild() ノードの最初の子を得る
Node Node getNextSibilig() ノードの次の兄弟を得る
Node Node getNodeType() ノードのノードの種類を得る
Node short getNodeName() ノードのノード名を得る
Node String getNodeValue() ノードのノード値を得る

読み込むXMLファイルは以下のproject.xmlで、ここにあるlog4jのバージョンをJavaで読み込んで取得したい。

<?xml version="1.0" encoding="Shift_JIS"?>
<project>
    <pomVersion>3</pomVersion>
    <name>hoge</name>
    <id>hoge</id>
    <groupId>Hoge</groupId>
    <currentVersion>1.2.0</currentVersion>
    <organization>
        <name>Hoge Project</name>
        <url>http://hogehogefuga.sourceforge.jp/</url>
    </organization>
    <inceptionYear>2003</inceptionYear>
    <package>jp.ossc.hoge</package>
    <dependencies>
        <dependency>
            <id>ant</id>
            <version>1.5</version>
        </dependency>

        <dependency>
            <id>junit</id>
            <version>3.8.1</version>
        </dependency>

        <dependency>
            <id>ejb</id>
            <version>2.1</version>
        </dependency>

        <dependency>
            <id>jta</id>
            <version>1.0.1</version>
            <url>http://java.sun.com/products/jta</url>
        </dependency>

        <dependency>
            <id>jms</id>
            <version>1.1</version>
        </dependency>

        <dependency>
            <id>servletapi</id>
            <version>2.4-20030804.000000</version>
        </dependency>

        <dependency>
            <id>log4j</id>
            <version>1.2.9</version>
        </dependency>
        
        <dependency>
            <groupId>jfreechart</groupId>
            <artifactId>jfreechart</artifactId>
            <id>jfreechart</id>
            <version>1.0.13</version>
            <type>jar</type>
        </dependency> 
        
        <dependency>
            <id>javasysmon</id>
            <version>0.3.3</version>
            <type>jar</type>
        </dependency>
    </dependencies>

</project>

まずXMLファイルのノードを順番にたどってみる。

package xml;

import java.io.FileInputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class XmlReader {
	private static String xmlFile;
	public static void main(String[] args) throws Exception {
		if (args.length < 1) {
			System.err.println("Usage: 引数1 xmlファイル");
			System.exit(-1);
		}
		xmlFile = args[0];
		parseXml(xmlFile);
	}
	
	private static void parseXml(String xmlFile) throws Exception {
		DocumentBuilderFactory dbf 
					= DocumentBuilderFactory.newInstance();
		DocumentBuilder db 
					= dbf.newDocumentBuilder();
		
		Document doc = db.parse(new FileInputStream(xmlFile));;
		
		Element root =doc.getDocumentElement();
		
		walk(root);
		
	}
	
	private static void walk(Node node) {
		for (Node ch = node.getFirstChild();   //指定されたノードの最初の子を取得して
				  ch != null;				   //子がいる限り
				  ch = ch.getNextSibling()) {  //兄弟をたどる
			System.out.println(ch.getNodeName());
		}
	}
}
#text
pomVersion
#text
name
#text
id
#text
groupId
#text
currentVersion
#text
organization
#text
inceptionYear
#text
package
#text
dependencies
#text

これだとまだまだ、versionにはたどり着かない。
ノードの旅はまだ続く。
1つメソッドを追加した。

package xml;

import java.io.FileInputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class XmlReader {
	private final static String DEPENDENCIES = "dependencies";
	private final static String DEPENDENCY = "dependency";
	private final static String VERSION ="version";
	private static String xmlFile;
	
	public static void main(String[] args) throws Exception {
		if (args.length < 1) {
			System.err.println("Usage: 引数1 xmlファイル");
			System.exit(-1);
		}
		xmlFile = args[0];
		parseXml(xmlFile);
	}
	
	private static void parseXml(String xmlFile) throws Exception {
		DocumentBuilderFactory dbf 
					= DocumentBuilderFactory.newInstance();
		DocumentBuilder db 
					= dbf.newDocumentBuilder();
		
		Document doc = db.parse(new FileInputStream(xmlFile));;
		
		Element root =doc.getDocumentElement();
		
		walk(root);
		
	}
	
	private static void walk(Node node) {
		for (Node ch = node.getFirstChild();   //指定されたノードの最初の子を取得して
				  ch != null;				   //子がいる限り
				  ch = ch.getNextSibling()) {  //兄弟をたどる
			//System.out.println(ch.getNodeName());
			//今度はdependenciesというノードに絞って解析する
			getSpecificNodeValue(DEPENDENCIES, ch.getNodeName(),ch);
		}
	}
	
	private static void getSpecificNodeValue(String targetNodeName, String nodeName, Node node) {
		if(nodeName != null) {
			if (targetNodeName.equals(nodeName)) {
				System.out.println(node.getNodeName()); //dependencies
				for (Node ch = node.getFirstChild();    //dependenciesの最初の子を取得する
						  ch != null;					//子がいる限り
						  ch = ch.getNextSibling()) {   //兄弟をたどる
					System.out.println(ch.getNodeName());
					getSpecificNodeValue(DEPENDENCY, ch.getNodeName(),ch);
				}
			}
		}
	}
}

これを実行すると、結果は以下の通り。

dependencies
#text
dependency
dependency
#text
id
#text
version

(省略)

ついにversionが見えてきた。
では、log4jのバージョンを取得する。

package xml;

import java.io.FileInputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class XmlReader {
	private final static String DEPENDENCIES = "dependencies";
	private final static String DEPENDENCY = "dependency";
	private final static String LOG4J = "log4j";
	private final static String VERSION ="version";
	private static String xmlFile;
	
	public static void main(String[] args) throws Exception {
		if (args.length < 1) {
			System.err.println("Usage: 引数1 xmlファイル");
			System.exit(-1);
		}
		xmlFile = args[0];
		parseXml(xmlFile);
	}
	
	private static void parseXml(String xmlFile) throws Exception {
		DocumentBuilderFactory dbf 
					= DocumentBuilderFactory.newInstance();
		DocumentBuilder db 
					= dbf.newDocumentBuilder();
		
		Document doc = db.parse(new FileInputStream(xmlFile));;
		
		Element root =doc.getDocumentElement();
		
		walk(root);
		
	}
	
	private static void walk(Node node) {
		for (Node ch = node.getFirstChild();   //指定されたノードの最初の子を取得して
				  ch != null;				   //子がいる限り
				  ch = ch.getNextSibling()) {  //兄弟をたどる
			//System.out.println(ch.getNodeName());
			//今度はdependenciesというノードに絞って解析する
			getSpecificNodeValue(DEPENDENCIES, ch.getNodeName(),ch);
		}
	}
	
	private static void getSpecificNodeValue(String targetNodeName, String nodeName, Node node) {
		if(nodeName != null) {
			if (targetNodeName.equals(nodeName)) {
				for (Node ch = node.getFirstChild();    //dependenciesの最初の子を取得する
						  ch != null;					//子がいる限り
						  ch = ch.getNextSibling()) {   //兄弟をたどる
					getSpecificNodeText(LOG4J, ch.getNodeName(), ch);
				}
			}
		}
	}
	
	private static void getSpecificNodeText(String targetNodeValue, String nodeName, Node node) {
		if(nodeName != null) {
			Node child = node.getFirstChild();
			while(child != null) {
				child = child.getNextSibling();
				//id要素がlog4jのもの
				if( child != null && "id".equals(child.getNodeName()) && targetNodeValue.equals(child.getTextContent())) {
					System.out.println(child.getTextContent()); //log4j
					Node sibling = child.getNextSibling();
					while(sibling != null) {
						if("version".equals(sibling.getNodeName())) {
							System.out.println(sibling.getNodeName()); //version
							System.out.println(sibling.getTextContent()); //1.2.9 やっと取れた!
						}
						sibling = sibling.getNextSibling();
					}
				}
			}
		}

	}
}

結果

log4j
version
1.2.9

やっとversion情報まで辿りつけた。
ちょっと強引で再利用のできないサンプルなので、再利用可能な使い方はあとで考える。<参考>

やさしいXML 第3版

やさしいXML 第3版