【Java入門】XMLの扱い方(DOM、SAX、プロパティファイルも解説)

こんにちは!フリーランスの長野です。

JavaでXMLファイルって使っていますか? XMLファイルは項目と値のセットを人やソフトウェアが読み込めるように構成することができるので、データの保存や設定値を保存する場合によく使われます。

この記事では、JavaでのXMLファイルの扱い方について

  • XMLとは?
  • XMLファイルを読み込む方法
  • XMLファイルへ出力する方法

といった基本的な内容から、

  • プロパティファイルに読み書きする方法
  • オブジェクトのSerialization

など応用的な内容についても解説していきます。今回はJavaでのXMLファイルの扱い方について、わかりやすく解説します。

なお、Javaの記事については、こちらにまとめています。

目次

XMLとは?

XMLとは、Extensible Markup Languageの略です。マークアップ言語ですので、WEBサイトのデザインで使われるHTMLと似ています。マークアップ言語とは、タグと値のセットで作られ、文章を構造化する言語のことです。

HTMLはブラウザが読み込むためのタグで構成されていますが、XMLは人やソフトウェアが読み込めるように構成することができます。以下はXMLファイルの簡単な例です。

Sample.xml:

<?xml version="1.0" encoding="UTF-8"?>
<info code="A0001">
    <name>Taro Yamada</name>
</info>

XMLファイルを読み込む方法

XMLファイルを扱う際に、Javaでは操作するAPIが主に2つ用意されています。DOMとSAXです。

DOMはDocument Object Modelの略で、要素がノードで表され、ノードの関係がノードツリーで表されます。ツリー構成はパソコン内のフォルダやファイルにも用いられています。

SAXはSimple API for XMLの略で、要素を先頭から順にひとつずつイベントの連続として読み込みます。それぞれの使い方についてみていきましょう。

DOM

まずはDOMのAPIを使う方法について説明します。XMLファイルを読み込む準備をします。javax.xml.parsersパッケージのDocumentBuilderクラスやDocumentBuilderFactoryクラスを使います。

次にorg.w3c.dom.Documentクラスを使ってXMLファイルを読み込みます。そしてorg.w3c.dom.Elementクラスを使って要素を取得します。

ノードの名前を取得するにはgetNodeNameメソッドを、属性値を取得するにはgetAttributeメソッドを使います。ノードのリストを取得するにはorg.w3c.dom.NodeListクラスを使います。サンプルコードで確認しましょう。

読み取るXMLファイルは先ほどのSample.xmlを使います。

import java.io.File;

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;
import org.w3c.dom.NodeList;

public class XMLsample {

    public static void main(String[] args) {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new File("Sample.xml"));

            Element element = doc.getDocumentElement();
            System.out.println("Node: " + element.getNodeName());
            System.out.println("code: " + element.getAttribute("code"));

            NodeList nodeList = element.getChildNodes();
            for(int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                if(node.getNodeType() == Node.ELEMENT_NODE) {
                    Element name = (Element)node;
                    if(name.getNodeName().equals("name")) {
                        System.out.println(name.getNodeName() + ": " + name.getTextContent());
                    }
                }
            }

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

    }

}

実行結果:

Node: info
code: A0001
name: Taro Yamada

SAX

次はSAXのAPIを使う方法について説明します。同じようにXMLファイルを読み込む準備をします。javax.xml.parsersパッケージのSAXParserクラスやSAXParserFactoryクラスを使います。

SAXのAPIの場合はorg.xml.sax.helpers.DefaultHandlerクラスを継承して、それぞれのイベントが発生した際の処理を記述します。例えば、ドキュメントの読み込みが開始された場合は、startDocumentメソッドに記述した内容が処理実行されます。

また開始ノードに達した場合は、startElementメソッドに記述した内容が処理実行されます。サンプルコードで確認しましょう。読み取るXMLファイルは先ほどのSample.xmlを使います。

import java.io.File;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

class XMLsample{

    public static void main(String[] args) {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            SAXParser parser = factory.newSAXParser();
            parser.parse(new File("Sample.xml"), new SAXsample());
        } catch (Exception e) {
            // TODO 自動生成された catch ブロック
            e.printStackTrace();
        }
    }

}

class SAXsample extends DefaultHandler{
    public void startDocument() {
        System.out.println("読み込み開始");
    }

    public void endDocument() {
        System.out.println("読み込み終了");
    }

    public void startElement(String uri, String localName, String qName, Attributes attributes) {
        System.out.println("Node: " + qName + " 開始");
        if(qName.equals("info")) {
            System.out.println(attributes.getQName(0) + ": " + attributes.getValue(0));
        }
    }

    public void endElement(String uri, String localName, String qName) {
        System.out.println("Node: " + qName + " 終了");
    }

    public void characters(char[] ch, int start, int length) {
        System.out.println(new String(ch, start, length));
    }
}

実行結果:

読み込み開始
Node: info 開始
code: A0001

    
Node: name 開始
Taro Yamada
Node: name 終了


Node: info 終了
読み込み終了

DefaultHandlerクラスのメソッドについては、こちらで詳しく解説していますので参考にしてください。

https://docs.oracle.com/javase/jp/8/docs/api/org/xml/sax/helpers/DefaultHandler.html

XMLファイルへ出力する方法

DOMのAPIを使ってXMLファイルへ出力する方法について説明します。XMLファイルへ出力する準備は読み込みとほぼ同じです。

ノードツリーを作成するために、createElement、setAttribute、appendChild、createTextNodeなどのメソッドが用意されています。作成したノードツリーをTransformerFactoryクラス、Transformerクラスを使って変換します。

サンプルコードで確認しましょう。

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

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

public class XMLsample {

    public static void main(String[] args) {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.newDocument();
                        
            Element info = doc.createElement("info");
            info.setAttribute("code", "A0001");
            doc.appendChild(info);
            Element name = doc.createElement("name");
            name.appendChild(doc.createTextNode("Taro Yamada"));
            info.appendChild(name);
            
            TransformerFactory tfFactory = TransformerFactory.newInstance();
            Transformer tf = tfFactory.newTransformer();
            
            tf.setOutputProperty("indent", "yes");
            tf.setOutputProperty("encoding", "UTF-8");
            
            tf.transform(new DOMSource(doc), new StreamResult(new File("Sample.xml")));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
}

実行結果(Sample.xml):

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<info code="A0001">
    <name>Taro Yamada</name>
</info>

プロパティファイルに読み書きする方法

Javaにはプロパティファイルと呼ばれるファイルがあります。定数や規定値などの設定を記載するファイルとしてよく使われます。このプロパティファイルをXML形式のファイルにする方法を説明します。

Java5からXML形式でもプロパティファイルを記述できるようにメソッドが追加されました。プロパティファイルを扱うにはjava.util.Propertiesクラスを使います。

XML形式のプロパティファイルを読み込むには、loadFromXMLメソッドを使います。XML形式のプロパティファイルに書き込むには、storeToXMLメソッドを使います。サンプルコードで確認しましょう。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class XMLsample {
 
    public static void main(String[] args) {
        Properties properties = new Properties();
        
        // プロパティファイルのパスを指定する
        String strpass = "Sample.xml";
        
        try {
            // 書き込み
            properties.setProperty("code", "A0001");
            properties.setProperty("name", "Taro Yamada");
            OutputStream ostream = new FileOutputStream(strpass);
            properties.storeToXML(ostream, "comment");
            
            // 読み込み
            InputStream istream = new FileInputStream(strpass);
            properties.loadFromXML(istream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // Mapに格納
        Map<String, String> propMap = new HashMap<>();
        for(Map.Entry<Object, Object> e : properties.entrySet()) {
            propMap.put(e.getKey().toString(), e.getValue().toString());
        }
        
        System.out.println(propMap);
    }
 
}

実行結果:

{code=A0001, name=Taro Yamada}

Sample.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>comment</comment>
<entry key="code">A0001</entry>
<entry key="name">Taro Yamada</entry>
</properties>

プロパティファイルについては、こちらで詳しく解説していますので、ぜひ参考にしてください。

オブジェクトのSerialization

JavaBeansの仕様に沿ったオブジェクトのデータをシリアライズ、デシリアライズする方法について説明します。シリアライズとはデータの永続化、つまりファイルに保存することです。

逆にファイルからデータを復元することをデシリアライズといいます。ちなみにシリアライズを直列化と説明されている場合もあります。この場合はファイルにデータを保存する際に、1列のデータ列に変換して保存することを指して直列化と説明されています。

JavaBeansのパッケージにはオブジェクトのデータをシリアライズ、デシリアライズするためにXMLEncoderクラスとXMLDecoderクラスが用意されています。クラス名にXMLが付いていますので、XML形式で書き出します。

XMLEncoderクラスはJavaBeansクラスのオブジェクトのデータをXML形式に変換するためのクラスです。同じようにXMLDecoderはXML形式で保存されたファイルからデータを復元するためのクラスです。使い方をサンプルコードで確認しましょう。

InfoBean.java:

import java.io.Serializable;
 
public class InfoBean implements Serializable {
    // static final long serialVersionUIDが必要
    private static final long serialVersionUID = 1L;
 
    // プロパティ(メンバ変数)の宣言
    private String code;
    private String name;
    
    // 引数なしコンストラクタの定義
    public InfoBean() {}
    
    // プロパティcodeのsetter、getter
    public void setCode(String code) {this.code = code;}
    public String getCode() {return this.code;}
    
    // プロパティnameのsetter、getter
    public void setName(String name) {this.name = name;}
    public String getName() {return this.name;}
}

BeanSample.java:

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
 
public class BeanSample {
 
    public static void main(String[] args) {
        String fileName = "Sample.xml";
 
        // オブジェクトを作成
        InfoBean info = new InfoBean();
        info.setCode("A0001");
        info.setName("Taro Yamada");
 
        // オブジェクトのデータを保存
        try {
            XMLEncoder encoder = new XMLEncoder(
                new BufferedOutputStream(
                    new FileOutputStream(fileName)
                )
            );
            encoder.writeObject(info);
            encoder.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
 
        // オブジェクトのデータを復元
        InfoBean new_info = null;
        try {
            XMLDecoder decoder = new XMLDecoder(
                new BufferedInputStream(
                    new FileInputStream(fileName)
                )
            );
            new_info = (InfoBean)decoder.readObject();
            decoder.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return;
        }
 
        System.out.println(new_info.getCode() + ", " + new_info.getName());
    }
 
}

実行結果:

A0001, Taro Yamada

Sample.xml:

<?xml version="1.0" encoding="UTF-8"?>
<java version="10.0.1" class="java.beans.XMLDecoder">
 <object class="InfoBean">
  <void property="code">
   <string>A0001</string>
  </void>
  <void property="name">
   <string>Taro Yamada</string>
  </void>
 </object>
</java>

JavaBeansについては、こちらで詳しく解説していますので、ぜひ参考にしてください。

まとめ

ここではJavaでのXMLファイルの扱い方について説明しました。XMLファイルは項目と値がセットになったデータを人やソフトウェアが読み込めるように構成することができるので便利です。使いこなすことができるように、この記事を何度も参考にして下さいね!

この記事を書いた人

熊本在住のフリープログラマ兼ライターです。C/C++/C#、Java、Python、HTML/CSS、PHPを使ってプログラミングをしています。専門は画像処理で最近は機械学習、ディープラーニングにはまっています。幅広くやってきた経験を活かしてポイントをわかりやすくお伝えしようと思います。
お問合せはこちらでも受け付けています。
info@sss-lab.com

目次