応用Java (Java/XML)

第5回 2007年5月25日
「XMLパーサ」-- Java でXMLを処理
javax.xml.stream パッケージのパーサ
イベントの種類の調べる
 空白文字のチェック
 属性の処理
 応用(1) – テーブルの利用
「要素の出現回数を調べる」
java.util.Map, java.util.Set







javax.xml.stream の処理の応用(2)
フィルタ的な処理
MS Office 2007 のXMLを解析する
java.util.Collection のフレームワーク
Set, HashSet, SortedSet
Map, HashMap, TreeMap
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 = …..;
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

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;

StartElement
要素の名前 getName()
開始タグ内の属性リスト getAttributes()

属性を持つ要素の例
<image source="java.png" height="400" >
</image>



後で必要になる情報を記憶する(テーブルに)
複数のデータを記憶
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 は表に出ない
「フィルタ」とは?
与えられた入力内容を変換して出力
入力=>[処理内容]=>出力
 例:
一部分の取り出し
並べ替え
特定のパターンの検出
特定のパターンの変換





平文のテキスト部分を取り出す
特定の名前の要素を取り出す
特定の名前の要素名を変換する


Characters のイベントを処理
getData()メソッドで内容を取り出す
if( event.isCharacters() ) {
Characters chars = (Characters)event;
if( !chars.isWhiteSpace() ) {
String text = chars.getData();
System.out.println( text );
}

対象はあらかじめテーブルに記憶
Map<String,String> map
= new TreeMap<String,String>();
map.put( "document" , "body" );
map.put( "title" , "h1" );
map.put( ":text" , "p" );


startElement, endElementを処理
getName() メソッドでチェック
StartElement se;
String name = se.getName().toString();
if( map.containsKey( name ) ) {
String value = map.get( name );
System.out.println( "<" + value + ">" );
}

処理をメソッドに分割する工夫
XMLEvent event = reader.nextEvent();
if( event.isStartElement() ) {
startElement( (StartElement)event );
} else if( event.isEndElement() ) {
endElement( (EndElement)event );
}
:
要素などの名前の衝突を避ける工夫
 「名前空間(Namespace)」=「住所」
 URN,URI で表現
 xmlns:ns=http://w3.org/Namespace
 「省略形」として「プレフィックス」

xmlns:v="urn:schemas-microsoftcom:vml"
:
<v:ab> abcd </v:ab>
javax.namespace.Qname クラス
正式なURIを含む情報を定められた形
式で記憶
 getLocalPart() -- 名前空間を含まない
部分の名前
 getPrefix() – 文書内のプレフィックス
の名前


MicroSoft Office 2007 からファイルの
保存形式の標準は XML
 複数の XMLを ZIP形式で保存
word -+- document.xml
+- fontTable.xml
+- settings.xml
+- styles.xml
+- WebSettings.xml

Jar ( Java Archive )
ファイルの保存形式はZIPを採用
 t オプション – 内容を調べる
 x オプション – 実際に展開
 使用例)

jar tvf Java.docx
jar xvf Java.docx
ZIP形式のファイルを直接処理する
ZipFile クラス – ZIP形式のファイル
ZipEntry クラス – 格納された個々の
ファイルやディレクトリ
 ZipEntry の集まりは
java.util.Enumeration
(古いスタイルだが、取り扱いは
java.util.Iterator とほぼ同じ)


