パーサの応用

Download Report

Transcript パーサの応用

第4回 2007年5月11日
「XMLパーサ」-- Java でXMLを処理
javax.xml.stream パッケージのパーサ
XMLEventReader と XMLInputFactory
(「Factory のデザインパターン」)
XMLEventReader と java.util.Iterator
javax.xml.stream.events の XMLEvent
 イベントの種類の調べる
 空白文字のチェック
 属性の処理


javax.xml.stream による処理の応用
文書の情報を何度も利用するには?
変数やテーブルの活用
 java.util.Collection のフレームワーク
Set, HashSet
Iterator
Map, HashMap


XML文書内の字句を解析
要素、属性などの情報を取り出す
(アプリケーションが1文字ずつの処
理を行う必要はない)
<doc>
<title> Java and XML </title>
<image source=“jax.png” />
</doc>


標準のクラスライブラリで提供
(新しくパーサを設計する必要なし)
 複数の種類(標準的な処理パターン)
SAX(Simple API for XML)
DOM(Document Object Model)
javax.xml.streamパッケージ

javax.xml.stream
XMLEventReader インタフェース
XMLInputFactory クラス
 javax.xml.stream.events
XMLEvent インタフェース
サブインタフェース群
StartDocument, EndDocument,
StartElement, EndElement, Characters


XMLEventReader インタフェース
構文解析を実行(つまりパーサ)
java.util.Iterator として扱える
=発見した要素などの構成要素の集まり
(つまり、処理結果のデータでもある)
hasNext()メソッド、 next()メソッド
nextEvent()メソッド
<doc><title>ABC</title></doc>


XMLInputFactory クラス
XMLEventReader のインスタンスを得るた
めの専用のクラス
=それ自身は処理を実行するわけではない
会社の「受付係」、「案内係」の役割
XMLInputFactory factory =
XMLInputFactory.newInstance();
XMLEventReader reader =
factory.createXMLEventReader( source );


Factoryクラスはまず自分のインスタンス
を作る
Factoryのインスタンスから実際に処理を
行うインスタンスを得る
「実装クラス」の実体を隠す(なぜ?)
XMLEventReader reader
= new XMLEventReader( source );
とはしない
 XMLEventReader はインタフェース(抽象化)
実装クラスを交換可能
実行環境によって実装クラスが異なる場合
にも柔軟に対応

XMLEventReader reader = …..;
while( reader.hasNext() ) {
XMLEvent event = reader.nextEvent();
System.out.println( event );
}
<doc><title>ABC</title></doc>




XMLEventReader がかかえるデータ
javax.xml.stream.events パッケージが提供
XMLEvent が共通のスーパインタフェース
StartDocument, EndDocument
StartElement, EndElement
Characters, Comment
Attribute など
<doc><title>ABC</title></doc>

XMLEventReaderTest1.java
import javax.xml.stream.*;
import javax.xml.stream.events.*;
import javax.xml.transform.stream.*;
public class XMLEventReaderTest1 {
public static void main( String[] args ) {
try {
StreamSource source
= new StreamSource( args[0] );
XMLInputFactory factory
= XMLInputFactory.newInstance();
XMLEventReader reader
= factory.createXMLEventReader(
source );
int count=0;
while( reader.hasNext() ) {
XMLEvent event = reader.nextEvent();
System.out.println( "Event " + count
+ ":" + event );
count++;
}

sample1.xml
<document>
<title>Java and XML</title>
Let's begin, now!
</document>
Event 0: <?xml version=“1.0” encoding=“UTF-8” ?>
Event 1: <document>
Event 2:
Event 3:<title>
Event 4: Java and XML
Event 5: </title>
Event 6: Let’s begin, new!
Event 7: </document>
Event 8: ENDDCUMENT
Event 0: 文書の開始 (StartDocument)
XML文書の性質についての情報
version, encoding, standalone
 Event 2: 改行文字(Characters)
人間に見やすくするだけのものだが
コンピュータにとってはテキスト
 Event 8: 文書の終了(EndDocument)

sample2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- This is a comment. -->
<document>
<title>Java and XML</title>
Let's begin, now!
</document>

sample2.xml
Event 0:<?xml version="1.0" encoding="UTF-8"?>
Event 1:<!-- This is a comment. -->
Event 2:<document>
Event 3:
Event 4:<title>
Event 5:Java and XML
Event 6:</title>
Event 7:Let's begin, now!
Event 8:</document>
Event 9:ENDDOCUMENT


XMLEvent の getEventType()メソッド
System.out.println( "Event " + count
+ ":" + event.getEventType() );
Event 0: 7
Event 1: 1
Event 2: 4
 イベントタイプの定数値と比較
private static String typeToString( int type ) {
switch( type ) {
case XMLEvent.START_DOCUMENT:
return "StartDocument";
:
case XMLEvent.CHARACTERS:
return "Caracters";
default:
return "Others";
}
}

XMLEvent に定義されたメソッド
isStartElement() など boolean型の返り値
if( event.isStartDocument() ) {
return "Start Document”;
}
else if( event.isEndDocument() ) {
return "End Document";
}
:
StartDocument sdevent;
String version = sdevent.getVersion();
return "Start Document:version=" + version;
if( event.isStartDocument() ) {
String version =
((StartDocument)event).getVersion();
return "Start Document:version=" + version;
}

Characters
テキストの内容 getData()
改行・空白のみかの判定 isWhiteSpace()
if( event.isCharacters() ) {
String data="";
if( ((Characters)event).isWhiteSpace() )
data = "White Space";
else
data = ((Characters)event).getData();
return "Text:" + data;




データの型を変える働き
なぜ型を変える必要が?
1つのデータが異なる型に同時になるこ
とはないはず
例)
int x; String s;
x = s; // エラー

型の継承関係 – 1つのデータが複数の型で
表現される
親クラス
子クラス





例) Characters extends XMLEvent
Characters は XMLEvent から「派生」
Characters は XMLEvent でもある!
Characters cs1;
XMLEvent xe = cs1; //キャストは省略可
Characters cs2 = (Characters)xe; //必ず必要

XMLEvent xe ;
xe.isWhiteSpace(); // このままでは間違い
Characters cs = (Characters)xe;
cs.isWhiteSpace(); // これは正しい

上と同じ内容を省略して書くと
XMLEvent xe;
((Characters)xe).isWhiteSpace();

StartElement
要素の名前 getName()
開始タグ内の属性リスト getAttributes()

属性を持つ要素の例
<image source="java.png" height="400" >
</image>
属性 Attribute も XMLEvent
Attributeは StartElementの内部に存在
(XMLEventReaderから直接取り出せない)
 Attribute の個数・順序は任意
再度 java.util.Iterator が登場



java.util.Iterator
複数のデータを1個ずつ順にたどる
(配列のように「何番目」の指定はない)
Iterator it;
while( it.hasNext() ) {
Object obj = it.next();
}

Iterator からの取り出しせる型は任意
Object 型を Attribute に「キャスト」する
Object obj = it.next();
Attribute attr = (Attribute)obj;

Attribute
属性の名前 getName();
属性の値
getValue();
while( it.hasNext() ) {
Object obj = it.next();
if( obj instanceof Attribute ) {
Attribute attr = (Attribute)obj;
String name = attr.getName().toString();
String value = attr.getValue();
System.out.println( name + "=" + value );
}
}

sample3.xml
<document>
<title>Java and XML</title>
Let's begin, now!
<image source="java.png“ height="400"
width="512" />
</document>

属性の登場順序は意味を持たない
height=400
source=java.png
width=512

登場順ではなくアルファベット順?

後で必要になる情報を記憶する(変数に)
int allCount=0; // 全イベントの個数を記憶
int eleCount=0; // 要素(開始タグ)の個数を記憶
while( reader.hasNext() ) {
XMLEvent event = reader.nextEvent();
allCount++;
if( event.isStartElement() ) {
eleCount++;
}



後で必要になる情報を記憶する(テーブルに)
複数のデータを記憶
java.util.Collection, java.util.List, java.util.Set
複数のペアのデータの表
java.util.Map (キーと値、キー全体は Set )
値
キー
•
•
•
•
<document>
<tytle>
<image>
<text>
•
•
•
•
1
1
2
4

変数ではなく Mapを用意
Map<String,Integer> map
= new HashMap<String,Integer>();
while( reader.hasNext() ) {
XMLEvent event = reader.nextEvent();
if( event.isStartElement() ) {
String name = ((StartElement)event)
.getName().toString();
saveToTable( name, map );
}
Mapへの格納方法
// 既に格納されている時ー 値を1増やす
if( map.containsKey( name ) ) {
Integer i = map.get( name );
map.put( name, new Integer( i+1 ) );
}
// 格納されていないー新たに値1で格納
else {
map.put( name, new Integer( 1 ) );
}


Mapに記憶された値の利用
Set<String> keys = map.keySet();
Iterator<String> it = keys.iterator();
while( it.hasNext() ) {
String key = it.next();
Integer value = map.get( key );
System.out.println( key + "=" + value );
}

Collection の処理を簡潔に記述
Set<String> keys = map.keySet();
for( String key : keys ) {
Integer value = map.get( key );
System.out.println( key + "=" + value );
}

カウンタ変数、Iterator は表に出ない