倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

7. javax.xml.transform とのブリッジ (1) : Source

今回と次回で、javax.xml.transform パッケージのクラスへのブリッジを考えます。 基本的な考え方は XMLEvent がベースです。 定義するクラスは XMLEvent を読み込む XMLEventSource と XMLEvent を書き出す XMLEventResult です。

今回は javax.xml.transform.Source インターフェース。

XMLEventSource


まず、「こんな風に使えるようにしよう」というサンプルコード。 XMLEventSource クラスは Source のサブタイプです。

public void someMethod(XMLEventIterator iterator){
    Source src = new XMLEventSource(iterator);
    ...
}

XMLEventIterator オブジェクトから Source オブジェクトを生成しています。 前回までに作成したクラス群では XMLEventIterator オブジェクトの生成に Source オブジェクトを使用していたので、正直これはあまり使いようがないかも。 XMLEventParser 以外で XMLEventIterator を生成するクラスなどを作成すれば使えますよって程度です。

まぁ、ともあれこの実装を考えていきましょう。

XMLEventSource の実装


新に Source オブジェクトを一から作成するのは大変なので、既にあるプル・パース型の Source クラス、javax.xml.transform.stax.StAXSource を利用しましょう。 StaxEventReader は javax.xml.stream.XMLEventReader を実装したクラスで、後ほど詳しくみていきます。

package xmlparsing.transform;

import javax.xml.stream.XMLStreamException;
import javax.xml.transform.stax.StAXSource;
import xmlparsing.XMLEventIterator;
import xmlparsing.stax.StaxEventReader;

public class XMLEventSource extends StAXSource{

    public XMLEventSource(XMLEventIterator iterator)throws XMLStreamException{
        super(new StaxEventReader(iterator));
    }
}

StaxEventReader


これは javax.xml.stream.XMLEventReader を実装し、その処理(XML イベントの列挙)を XMLEventIterator へ委譲するクラスです。 同じ XMLEvent という名前の型でも別の型なので、オブジェクトの変換(生成)が必要です。 StaxEventReader の実装は以下のようになります(いくつかメソッドの実装を略しています):

package xmlparsing.stax;

import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import xmlparsing.XMLEventIterator;

public class StaxEventReader implements XMLEventReader{
    
    private final XMLEventIterator iterator;
    private XMLEvent next;

    public StaxEventReader(XMLEventIterator iterator){
        this.iterator = iterator;
        
        if(iterator.hasNext())
            this.next = toStaxEvent(iterator.next());
    }

    public boolean hasNext() {
        return this.next != null;
    }

    public Object next() {
        try{
            return nextEvent();
            
        }catch(XMLStreamException ex){
            throw new RuntimeException(ex);
        }
    }

    public XMLEvent nextEvent() throws XMLStreamException {
        XMLEvent nextEvent = this.next;
        
        if(this.iterator.hasNext())
            this.next = toStaxEvent(this.iterator.next());
        
        return nextEvent;
    }
    
    /**
     * xmlparsing.events.XMLEvent オブジェクトから 
     * (javax.xml.stream.events.)XMLEvent オブジェクトを生成するメソッド。
     */
    private static XMLEvent toStaxEvent(xmlparsing.events.XMLEvent event){...}

    public void close() throws XMLStreamException {
        this.iterator.close();
    }

    public Object getProperty(String name) throws IllegalArgumentException {}

    public XMLEvent nextTag() throws XMLStreamException {...}
    public String getElementText() throws XMLStreamException {...}
    public XMLEvent peek() throws XMLStreamException {...}

    public void remove() {
        throw new UnsupportedOperationException();
    }
}

XMLEventReader インターフェースには、実装が少々難しい(メンドクサイ)メソッドもありますが、XMLEventReader も XMLEventIterator もプル・パース API なので、論理的に難しいところはあまりないでしょう。 

XMLEventReader に定義されている便利そうなメソッドは XMLEventIterator にも定義しておくのも良いかもしれません。

次回は javax.xml.transform.Result を実装したクラスを考えます。