JavaのプログラムからXML文書(ファイル)にアクセスする手段は、XML文書を処理するXMLプロセッサに依存します。J2SEでは標準APIとしてJAXPを提供しており、特定のXMLプロセッサに依存することなくXML文書を読み込むことができます。
WebアプリケーションにおいてXML文書を利用する機会が増えており,XML文書を利用するためのソリューションも整いつつあります。ここでは,XML文書を利用するための基礎として,DOM(Document Object Model)によるXML文書の読み込み方法を紹介します。なお,XML文書の基本的な読み込み方法としては,DOMのほかにSAX(Simple API for XML)を利用する方法もあります。次の表は,DOMとSAXの一般的な特徴を整理したものです。
表1 DOMとSAXの違い
DOM | SAX | |
---|---|---|
APIの特徴 | ツリー構造に基づくAPI | イベント駆動型API |
XML文書へのアクセス | XML文書の解析後にアクセス可能 | 基本的にXML文書の解析中のみ |
ツリー構造 | 保持する | 保持しない |
メモリー使用量 | XML文書に依存 | XML文書の大きさに関わらず少ない |
大きなXML文書 | あまり向かない | 向いている |
JAXPとDOMによってXML文書を読み込む場合は,リスト1に示すようにjavax.xml.parsers.DocumentBuilderFactoryオブジェクトを作り,さらにjavax.xml.parsers.DocumentBuilderオブジェクトを作ります。
リスト1 DOMを使ったXML文書の読み込み(抜粋)
String url = "test.xml";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(url); // XML文書をパース
Element element = doc.getDocumentElement(); // ルート要素の取得
NodeList list = element.getChildNodes(); // 子要素を含んだノードを列挙
Node node;
for (int iNode=0; (node = list.item(iNode))!=null; iNode++) {
// ノードの処理
}
太字のDocumentBuilder#parseメソッドが,実際にXML文書を読み込みパース(解析)する部分です。パースした結果をorg.w3c.dom.Documentオブジェクトに格納しています。このDocumentオブジェクトは,XML(またはHTML)文書全体を表すもので,これを使って文書ツリーにアクセスします。具体的には,Document#getDocumentElementメソッドを使ってルート要素(org.w3c.dom.Elementオブジェクト)を取得。次にElement#getChildNodesメソッドでその要素を構成する子ノード一覧を表すorg.w3c.dom.NodeListオブジェクトを取得し,各ノードにアクセスします。
ノードから取得できる情報は,ノード型(nodeType)によって異なります。
表2 ノードが保持する情報(値)の違い
型 | 名前 | 値 | 属性 |
---|---|---|---|
ATTRIBUTE_NODE | 属性名 | 属性値 | null |
CDATA_SECTION_NODE | "#cdata-section" | CDATAセクションのコンテンツ | null |
COMMENT_NODE | "#comment" | コメントのコンテンツ | null |
DOCUMENT_NODE | "#document" | null | null |
DOCUMENT_FRAGMENT_NODE | "#document-fragment" | null | null |
DOCUMENT_TYPE_NODE | 文書型名 | null | null |
ELEMENT_NODE | タグ名 | null | NamedNodeMap |
ENTITY_NODE | エンティティ名 | null | null |
ENTITY_REFERENCE_NODE | 参照されるエンティティの名前 | null | null |
NOTATION_NODE | 表記法名 | null | null |
PROCESSING_INSTRUCTION_NODE | ターゲット | ターゲットを除くすべてのコンテンツ | null |
TEXT_NODE | "#text" | テキストノードのコンテンツ | null |
次にサンプルのXML文書を示します。
リスト2 テスト用のXML文書
<?xml version="1.0" encoding="utf-8" ?>
<data>
<item type="private">
<title>asahi.com</title>
<link>http://www.asahi.com/</link>
<description />
</item>
</data>
DOMでは,XML文書を細分化し,それぞれをノードとして扱います。たとえばルート要素であるdataやその子要素であるitemは,ノード型ELEMENT_NODEのノードとなり,item要素の属性であるtypeはノード型ATTRIBUTE_NODEのノードとなります。また,要素の内容を示すasahi.comやhttp://www.asahi.com/はTEXT_NODEのノードとなります。このほか,タグとタグの間にある改行やスペースもTEXT_NODEのノードとして扱われます。
具体的にプログラムを見てみましょう。リスト3は,item要素の属性とその子要素の内容を取得するものです。
リスト3 DOMを使った要素の属性と内容の取得(抜粋)
Element element = doc.getDocumentElement(); // ルート要素の取得
NodeList list = element.getChildNodes(); // 子要素を含んだノードを列挙
Node node;
for (int iNode=0; (node = list.item(iNode))!=null; iNode++) {
String nodeName = node.getNodeName();
if (nodeName.equals("item")) {
System.out.println(nodeName);
// (1)要素の属性を取得
NamedNodeMap attrMap = node.getAttributes();
int attrs = attrMap.getLength();
for (int iAttr=0; iAttr<attrs; iAttr++) {
Node attr = attrMap.item(iAttr);
System.out.println(
attr.getNodeName() + "=" + attr.getNodeValue());
}
// (2)子要素を取得
NodeList childNodes = node.getChildNodes();
Node childNode;
for (int iItem=0;
(childNode = childNodes.item(iItem))!=null; iItem++) {
String childName = childNode.getNodeName();
if (childNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
String value = null;
try {
value = childNode.getFirstChild().getNodeValue();
}
catch (NullPointerException e) {
// 内容なし
}
System.out.println(
childNode.getNodeName() + ">"+ value);
}
}
}
}
要素の属性は,getAttributesメソッドを使ってorg.w3c.dom.NamedNodeMapオブジェクトを取得します。ここではすべての属性(ノード)を順番に取得していますが,NamedNodeMap#getNamedItemメソッドに属性名を与えてその属性を取得することも可能です。
子要素の取得は,ルート要素の場合と同じNode#getChildNodesメソッドを使います。ここでは,ノード型を取得して要素(ELEMENT_NODE)であれば,その子ノード(TEXT_NODE)の値を取得して表示しています。リスト2の
リスト3を実行すると,コンソールには次のように表示されます。リスト2がパースされ,要素の属性や内容を取得できていることがわかります。
item
type=private
title>asahi.com
link>http://www.asahi.com/
description>null
「JAVA Developer」より毎週役立つJava Tipsを配信中。ほかにも参考になるTipsは、JAVA Developerサイトのバックナンバーから探すことが可能です。
Copyright(C) 2010 SOFTBANK Creative Inc. All Right Reserved.