
XML ブログ記事 一覧
JavaでXML文章解析-SAX編
- 2010年9月 5日 12:39
- XML
今やXMLは様々なシステムに取り入れられています。![]()
その主な用途にアプリケーションの設定管理、
また使用データの管理が挙げられます。
XML文章(XMLファイルに記載されたデータ)を解析し
必要となるデータを取得する処理は、
開発基盤となっているフレームワークや各種アプリケーション部で
自動的に行ってくれている部分も少なくありません。
例えば、JavaのWebシステムを動作させるApache Tomcatは
自身が起動された際にweb.xmlというシステムの設定ファイルを解析します。
解析時に問題があるとApache Tomcatはその詳細を出力し、
システムを起動させません。
・Apache Tomcatの解析エラー時の出力例
致命的: アプリケーションのweb.xmlファイル jndi:/localhost/
test01/WEB-INF/web.xml の解析エラーです
org.xml.sax.SAXParseException:以下略・・・・・
「org.xml.sax.SAXParseException」は解析時の問題、
そして解析方法を表しています。
JavaでXML文章を解析する方法には、DOM、SAX、StAX等がありますが、
Apache Tomcatのweb.xml解析にはSAXを用いていることが分かります。
この記事ではJavaによるSAXを用いたXML解析について
シンプルなサンプルを基に説明します。
SAX(Simple API for XML)は、XML文章を解析する
API(クラスやインターフェスの集まり)の1つです。
XML文章を先頭から順に読み込み、発生したイベントを
イベント毎に定義したメソッドによって処理し、
プログラムにその解析内容伝達します。
イベントとは、
- 「XML文章の読み込みを開始した」
- 「開始タグを読み込んだ」
- 「終了タグを読み込んだ」
- 「文章があった」
などです。
SAXは二つの部分から成ります。
解析を行いイベントを生成する「SAXパーサ」、
SAXパーサからイベントを受け取りイベント毎の処理を行う「イベントハンドラ」です。
SAXパーサはJ2SE1.4以降であれば標準で含まれています。
その他、Apache Xerces Projectが公開している
Xerces2 というSAXパーサもあります。
今回はこのXerces2を使用します。
これは別途ダウンロードが必要です。
http://xerces.apache.org/
ダウンロードページから Xerces2 Java 2.10.0 - zip を選択します。
(2010年8月時点)
適当な場所にダウンロードしたら、フォルダの中にある
- xercesImpl.jar
- xml-apis.jar
を、CLASSPATHに設定するか、JAVA_HOME/jre/lib/extに置いて下さい。
(例えば、C:\Program Files\Java\jdk1.5.0_14\jre\lib\extに置きます)
また、eclipseならば外部Jarファイルの追加で結構です。
参考:http://www6.airnet.ne.jp/manyo/xml/sax/step7.html
実際にXMLファイルを読み込み解析するのはXMLReaderクラスです。
このクラスはXMLReaderFactoryクラスがSAXパーサを元に生成します。
イベントハンドラは独自のクラスとして作成する必要があります。
その際、org.xml.sax.helpers.DefaultHandlerクラスを継承します。
イベントハンドラクラスはDefaultHandlerクラスの、
各種イベント処理を行うメソッドをオーバーライドしなければなりません。
そしてイベントハンドラクラスは、XML文章を解析するXMLReaderクラスから
イベント処理の命令を受け対応するイベント処理を行います。
それでは、今回作成するプログラムを見ていきましょう。
以下の、KENスクール校舎情報を持つXML文章を読み込み画面に出力します。
■動作環境
OS : Windows XP
J2SE : 1.5
eclipse : 3.5
■ファイル名:schools.xml
<schools>
<school id="1">
<name>新宿校</name>
<zipcode>1600023</zipcode>
<address>
東京都新宿区西新宿1-10-1 MY新宿第2ビル 9F
</address>
<tel>0353817072</tel>
</school>
<school id="2">
<name>池袋校</name>
<zipcode>1700013</zipcode>
<address>
東京都豊島区東池袋1-12-8 富士喜ビル 5F
</address>
<tel>0359570959</tel>
</school>
<school id="3">
<name>渋谷校</name>
<zipcode>1500002</zipcode>
<address>
東京都渋谷区渋谷1-14-11 小林ビル 6F
</address>
<tel>0354683570</tel>
</school>
<school id="4">
<name>北千住校</name>
<zipcode>1200034</zipcode>
<address>
東京都足立区千住2-59 金子ビル 5F
</address>
<tel>0358133316</tel>
</school>
</schools>
■実行結果
■作成するクラス
・SAXSampleMain(実行クラス)
・MySAXHandler(イベントハンドラクラス)
■フォルダ階層

■実行クラス
package test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import handler.MySAXHandler;
//XML文章の解析と結果を画面表示するクラス。
public class SAXSampleMain {
//使用するSAXパーサ
private static final String PARSER_NAME =
"org.apache.xerces.parsers.SAXParser";
/*
* XML文書からデータを抽出し画面に表示する。
*/
public static void main(String[] args) {
//読み込むXMLファイルパス
final String xmlFilePath = "./src/res/schools.xml";
try{
//XMLパーサの生成
final XMLReader parser =
XMLReaderFactory.createXMLReader(PARSER_NAME);
//イベントハンドラオブジェクト
MySAXHandler handler = new MySAXHandler();
//XMLパーサにイベントハンドラを登録
parser.setContentHandler(handler);
//XML文章解析を実行するスレッド
Thread thread1 = new Thread(){
public void run(){
try{
//XMLを解析する
parser.parse(xmlFilePath);
}
catch(SAXException se){
se.printStackTrace();
}
catch(IOException ie){
ie.printStackTrace();
}
}
};
//スレッドを起動
thread1.start();
/*
* メインスレッドはthread1が終了するまで待機し
* thread1が実行開始
*/
thread1.join();
//XML文章データをイベントハンドラオブジェクトから取得
ArrayList<LinkedHashMap> list = handler.getList();
// 画面出力処理
// 改行コード
String br = "\n";
// タブ
String tb = "\t";
// 行区切り線の作成
StringBuffer sbHr = new StringBuffer("-");
for(int i = 0; i < 100; i++){
sbHr.append("-");
}
//行区切り線
String hr = sbHr.toString();
//出力文字列
StringBuffer xmlData = new StringBuffer();
//項目作成 全角スペースを半角スペースに変更
xmlData.append(
//右詰4桁
String.format("%4s", " 校舎番号").replace(" ", " ")
//右詰6桁
+ String.format(" %6s"," 校舎名").replace(" ", " ")
//右詰9桁
+ String.format(" %9s", "郵便番号"+ tb).replace(" ", " ")
//左詰30桁
+ String.format(" %-30s", tb + "住所").replace(" ", " ")
//右詰12桁
+ String.format(" %12s", " 電話番号 ").replace(" ", " ")
);
//改行コードとタブを付加
xmlData.append(br);
xmlData.append(hr);
xmlData.append(br);
/*
* <school>毎のデータを取得し、出力する文字列を作成する 。
* LinkedHashMap<キー,データ>
*/
for(LinkedHashMap<String,String> map : list){
//キーのリストを取得する
LinkedHashSet<String> tags = new LinkedHashSet<String>(map.keySet());
//キー毎に表示文字列の桁数を調整する
for(String tag : tags){
String data = "";
if(tag.equals("id")){
//右詰4桁
data = String.format("%4s", map.get(tag));
}
else if(tag.equals("name")){
//左詰6桁
data = String.format("%6s", map.get(tag));
}
else if(tag.equals("zipcode")){
//右詰8桁
data = String.format(" %8s", map.get(tag));
}
else if(tag.equals("address")){
//左詰30桁
data = String.format(" %-30s", map.get(tag)) ;
}
else if(tag.equals("tel")){
data = tb + map.get(tag) ;
}
//半角スペースを全角スペースに置き換える
xmlData.append(data.replace(" ", " ") );
}
//改行コードとタブを付加
xmlData.append(br);
xmlData.append(hr);
xmlData.append(br);
}
//画面に出力
System.out.println(xmlData.toString());
}
catch(SAXException se){
se.printStackTrace();
}
catch(InterruptedException ie){
ie.printStackTrace();
}
}//end main
}// end class SAXSampleMain
■イベントハンドラクラス
package handler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.ArrayList;
import java.util.LinkedHashMap;
/*
* イベントハンドラクラス。
* イベント処理を行い、解析したXML文章のデータを管理する
*/
public class MySAXHandler extends DefaultHandler {
//XML文章のデータを管理する
ArrayList<LinkedHashMap> xmlData = null;
//schoolタグの子要素を管理する
LinkedHashMap<String,String> school = null;
//処理中のタグ名
String current_tag = "";
//XML解析結果を返す
public ArrayList<LinkedHashMap> getList(){
return xmlData;
}
//XML文章読み込み開始
@Override
public void startDocument() throws SAXException {
xmlData = new ArrayList<LinkedHashMap>();
}
//XML文章読み込み終了
@Override
public void endDocument() throws SAXException {
current_tag = "";
}
//XML開始タグ読み込み
@Override
public void startElement(String uri, String localName,
String qName,Attributes attributes) throws SAXException {
//参照しているタグ名を登録
current_tag = qName;
/* schoolタグを読み込み時にschoolタグの子要素のデータを入れる
オブジェクトを生成
*/
if(qName.equals("school")){
//schoolタグの子要素の名前をキー値として子要素のデータを登録する
school = new LinkedHashMap<String,String>();
//schoolタグのid属性の値を登録
school.put(attributes.getQName(0), attributes.getValue(0));
}
}
//XML終了タグ読み込み
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
//参照しているタグが</school>のとき、1校舎分のデータ読み込み修了
if(qName.equals("school")){
xmlData.add(school);
}
}
/*
* schoolタグの子要素データを属性名、タグ名をキー値として保存する。
* データ:ch[start]からlength分
* (例)<name>新宿校</name>
* データ:新宿校
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if(current_tag != null && !"schools".equals(current_tag)
&& !"school".equals(current_tag)){
//キー値が登録済みでなければ新規追加
if(!school.containsKey(current_tag)){
school.put(current_tag, new String(ch,start,length));
}
}
}
}// end class MySAXHandler
MySAXHandlerクラスは読み込んだXML文章のデータも管理します。
管理方法として今回は、schoolタグ内のデータを
LinkedHashMapオブジェクトに格納し、
LinkedHashMapオブジェクトをArrayListオブジェクトに格納しています。
つまり、校舎データをArrayListオブジェクトに格納し管理しています。
SAXSampleMainクラスのメインスレッド(mainメソッド)で
スレッドthread1を生成しそのスレッドがXML文章の解析を行っています。
メインスレッドはthread1を起動後、
thread1の処理終了を待って残りの処理を再開します。
thread1.start();
thread1.join();
今回、XML文章を解析するという仕事とXML文章のデータを表示する
という仕事をスレッドに分担させてみました。
なお、スレッドをSAXSampleMainクラスとは別のクラスに定義すれば
コードの仕様変更時に柔軟に対処できるものになると思います。
紹介したサンプルソースはこちら
からダウンロードできます。
終わりに、XMLは冒頭にお伝えしたように
様々なアプリケーションやシステムで利用されています。
そして当然ながら使用されるプログラム言語も様々です。
既存のアプリケーションがXML解析処理を既に行ってくれる事も多いのですが、
そんな時だからこそ、XMLの解析・操作方法技術を知り
独自の仕様とすることは開発において有益ではないでしょうか。
また別な機会に、J2SE 6から登場したStAXについて紹介しようと思います。
--------------------------------------------------------------------------------
パソコンスクール KENスクール北千住校 Programインストラクター
http://www.kenschool.jp/school/kitasenju/index.html
KENスクールでXMLを学びたい方は、Program講座へ!
http://www.kenschool.jp/Program/index.html
- Comments (Close): 0
- TrackBacks: 0
なぜ今XMLDBなのか
- 2009年10月 5日 12:09
- XML
昨今、開発の現場で主に使用されているデータベースといえば、
OracleやMySQLを始めとする
リレーショナルデータベース(RDB)ではないでしょうか。
しかし、最近では従来のRDBに替わる技術としてXMLが注目されています。
XMLはデータ記述言語のSGMLを
WEB上で表現する手段として拡張したものです。
言語の仕様が固まったのが1998年なので誕生から約10年になりますね!![]()
XMLがテキストファイルであるという性質上、インターネットでつながっている
異なるPC同士でデータのやりとりを行う際に適したフォーマットを持つ点が
注目されがちです。
ですが、今回はRDBとの対比!ということで、
XMLをデータベースとして利用するXMLDBについて
掘り下げていきたいと思います。
では、本題!なぜ今XMLDBが注目されているのか?
これはIT業界の現状を見つめることで答えが見えてきます。
IT業界が『ドッグイヤー』であるという表現は、
次々新機能が搭載される電化製品から容易に想像できますが、
そのスピーディな変化に対応するには
柔軟で拡張が簡単なシステム構成が必要になります。
RDBでは『表』がデータを格納する単位である以上、
将来のデータ構造を見越した表定義が必須!!になり、
データベース設計に時間を割かなければいけませんでした。
ER図と格闘するKENのエンジニアを何度見たことか!
その点、XMLDBでは、
テキストファイルでデータが階層構造で記述されています。
そのため、データの追加や更新に手間がほとんどかからないため
柔軟で拡張が簡単なデータベース設計が可能です。
つまり、スピーディな変化が必須なIT業界の現状にマッチする
データベースモデルであると言えるでしょう。
・・・ちなみに!
RDBに対する問い合わせ言語と言えば!
ご存知の方も多いでしょう。ずばりSQLですね。
これに対し、XMLDBに対する問い合わせ言語と言えば!
XQueryと呼ばれる言語が該当します。
XQueryは現在、W3Cによって標準化されていて、
XMLDBエンジニアのための資格、
『XMLマスターデータベース』 でもXQueryは
必須の出題範囲となるくらいスタンダードなものです。
・・・JQueryと読み方が似てますが、全くの別物ですよ!
Oracle11gやOffice2007など
開発現場やIT企業で主流となっているソフトウェアも
次々とXMLとの互換を図ってきている今、
XMLDBがRDBのシェアと肩を並べるほどスタンダードな
データベースモデルになる日もそう遠くではないでしょう。
みなさんも新しいデータベースモデルに目を向ける
良いチャンスではないでしょうか?
--------------------------------------------------------------------------------
パソコンスクール KENスクール池袋校 Programインストラクター
http://www.kenschool.jp/school/ikebukuro/index.html
KENスクールでXMLを学びたい方は、Program講座へ!
http://www.kenschool.jp/Program/index.html
- Comments (Close): 0
- TrackBacks: 0





