Transcript パーサの応用
第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 とほぼ同じ)