注意:
WebLogic XML Streaming APIはWebLogic Serverリリース9.0の時点で非推奨となっています。かわりに、Java Community Processによる標準仕様Streaming API for XML (StAX)を使用してください。詳細は、「Streaming API for XML (StAX)の使い方」を参照してください。
この付録の内容は次のとおりです。
WebLogic XML Streaming APIは、XMLドキュメントを解析および生成するための簡単でわかりやすい手段を提供します。SAX APIと似ていますが、XMLドキュメントに対する手続き的なストリーム・ベースの処理が可能であり、SAXイベント・ハンドラを作成する必要はありません。SAXイベント・ハンドラで複雑なXMLドキュメントを扱うと、ハンドラ自体が複雑になる場合があります。つまり、Streaming APIを利用すれば、SAX APIよりきめ細かく解析を制御できます。
SAXを使用してXMLドキュメントを解析する場合、プログラムでは、イベント発生時に解析をリスニングするイベント・リスナーを作成し、特定のイベントを請求するのではなくイベントに対して対応する必要があります。一方、Streaming APIを使用する場合は、XMLドキュメントを手順の流れに沿って処理すること、特定のタイプのイベント(要素の開始など)を請求すること、要素の属性を繰返し処理すること、ドキュメントの先頭をスキップすること、任意の時点で処理を停止すること、特定の要素の下位要素を取得すること、指定どおりに要素をフィルタ処理することができます。イベントに対応するのではなく、イベントを請求するので、Streaming APIを使用する方法は、プル解析と呼ばれることもあります。
Streaming APIにより、オペレーティング・システム上のXMLファイル、DOMツリー、SAXイベントのセットなど、多くのタイプのXMLドキュメントを解析できます。これらのXMLドキュメントをイベントのストリーム、すなわちXMLInputStream
に変換し、このストリームを順に処理して、要素の開始、ドキュメントの終了などのイベントを必要に応じてスタックから取得します。
WebLogic Streaming APIは、デフォルト・パーサーとしてWebLogic FastParserを使用します。
ストリーミングAPIを使用したXMLドキュメント解析の完全なサンプルについては、ORACLE_HOME
\wlserver\samples\server
ディレクトリを参照してください(ここで、ORACLE_HOME
は、WebLogic Serverをインストールしたディレクトリ)。WebLogic Serverサンプル・コードの詳細は、『Oracle WebLogic Serverの理解』のサンプル・アプリケーションおよびサンプル・コードに関する項 を参照してください。
表B-1で、WebLogic Streaming APIの主なインタフェースとクラスについて説明します。
表B-1 XML Streaming APIのインタフェースとクラス
インタフェースまたはクラス | 説明 |
---|---|
XMLInputStreamFactory |
XMLドキュメント解析用の |
XMLInputStream |
イベントの入力ストリームを入れるために使用されるインタフェース。 |
BufferedXMLInputStream |
|
XMLOutputStreamFactory |
XMLドキュメント生成用の |
XMLOutputStream |
イベントを書き込むために使用されるインタフェース。 |
ElementFactory |
このAPIで使用されるインタフェースのインスタンスを作成するためのユーティリティ。 |
XMLEvent |
要素の開始、要素の終了など、XMLドキュメントでのすべてのタイプのイベントのための基本インタフェース。 |
StartElement |
|
AttributeIterator |
要素の属性のセットを繰返し処理するために使用されるオブジェクト。 |
Attribute |
要素の特定の属性を記述するオブジェクト。 |
以下のJavadocには、この章で説明したWebLogic XML Streaming API機能に加え、詳しく説明されていない機能に関するリファレンスが掲載されています。
以下の手順は、WebLogic XML Streaming APIによりXMLドキュメントの解析と操作を行う一般的手順について説明したものです。
最初の2つの手順は必須です。その後の手順は、XMLファイルをどのように処理するかに応じて実行します。
weblogic.xml.stream.*
クラスをインポートします。XMLEvent
タイプを返します。「ストリームの繰返し処理」を参照してくださいXMLEvent
タイプのそれぞれについて、イベント・タイプを判別します。イベント・タイプには、XMLドキュメント、要素の終了、エンティティ参照などがあります。「特定のXMLEventタイプの判別」を参照してください以下の節では、XML Streaming APIによりXMLドキュメントを解析する例を示します。
このプログラムは、XMLファイルを表す1つのパラメータを取り、そのファイルをXML入力ストリームに変換します。次に、ストリームを繰返し処理し、XML要素の開始、XMLドキュメントの終了など、各イベントのタイプを判別します。開始要素、終了要素、および要素の本文を形成する文字データの3つのタイプのイベントについては、情報が出力されます。コメントやXMLドキュメントの開始など、その他のタイプのイベントについては、何も行われません。
注意:
太字のコードについては、例の後の節で詳しく説明します。
package examples.xml.stream; import weblogic.xml.stream.Attribute; import weblogic.xml.stream.AttributeIterator; import weblogic.xml.stream.ChangePrefixMapping; import weblogic.xml.stream.CharacterData; import weblogic.xml.stream.Comment; import weblogic.xml.stream.XMLEvent; import weblogic.xml.stream.EndDocument; import weblogic.xml.stream.EndElement; import weblogic.xml.stream.EntityReference; import weblogic.xml.stream.ProcessingInstruction; import weblogic.xml.stream.Space; import weblogic.xml.stream.StartDocument; import weblogic.xml.stream.StartPrefixMapping; import weblogic.xml.stream.StartElement; import weblogic.xml.stream.EndPrefixMapping; import weblogic.xml.stream.XMLInputStream; import weblogic.xml.stream.XMLInputStreamFactory; import weblogic.xml.stream.XMLName; import weblogic.xml.stream.XMLStreamException; import java.io.FileInputStream; import java.io.FileNotFoundException; public class ComplexParse { /** * Helper method to get a handle on a stream. * Takes in a name and returns a stream. This * method usese the InputStreamFactory to create an * instance of an XMLInputStream * @param name The file to parse * @return XMLInputStream the stream to parse */ public XMLInputStream getStream(String name) throws XMLStreamException, FileNotFoundException { XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance(); XMLInputStream stream = factory.newInputStream(new FileInputStream(name)); return stream; } /** * Determines the type of event, such as the start * of an element, end of a document, and so on. If the * event is of type START_ELEMENT, END_ELEMENT, or * CHARACTER_DATA, the method prints out appropriate info; * otherwise, it does nothing. * @param event The XML event that has been parsed */ public void parse(XMLEvent event) throws XMLStreamException { switch(event.getType()) { case XMLEvent.START_ELEMENT: StartElement startElement = (StartElement) event; System.out.print("<" + startElement.getName().getQualifiedName() ); AttributeIterator attributes = startElement.getAttributesAndNamespaces(); while(attributes.hasNext()){ Attribute attribute = attributes.next(); System.out.print(" " + attribute.getName().getQualifiedName() + "='" + attribute.getValue() + "'"); } System.out.print(">"); break; case XMLEvent.END_ELEMENT: System.out.print("</" + event.getName().getQualifiedName() +">"); break; case XMLEvent.SPACE: case XMLEvent.CHARACTER_DATA: CharacterData characterData = (CharacterData) event; System.out.print(characterData.getContent()); break; case XMLEvent.COMMENT: // Print comment break; case XMLEvent.PROCESSING_INSTRUCTION: // Print ProcessingInstruction break; case XMLEvent.START_DOCUMENT: // Print StartDocument break; case XMLEvent.END_DOCUMENT: // Print EndDocument break; case XMLEvent.START_PREFIX_MAPPING: // Print StartPrefixMapping break; case XMLEvent.END_PREFIX_MAPPING: // Print EndPrefixMapping break; case XMLEvent.CHANGE_PREFIX_MAPPING: // Print ChangePrefixMapping break; case XMLEvent.ENTITY_REFERENCE: // Print EntityReference break; case XMLEvent.NULL_ELEMENT: throw new XMLStreamException("Attempt to write a null event."); default: throw new XMLStreamException("Attempt to write unknown event ["+event.getType()+"]"); } } /** * Helper method to iterate over a stream * @param name The file to parse */ public void parse(XMLInputStream stream) throws XMLStreamException { while(stream.hasNext()) { XMLEvent event = stream.next(); parse(event); } stream.close(); } /** Main method. Takes a single argument: an XML file * that will be converted into an XML input stream. */ public static void main(String args[]) throws Exception { ComplexParse complexParse= new ComplexParse(); complexParse.parse(complexParse.getStream(args[0])); } }
XML Streaming APIにより、XMLファイルDOMツリー、SAXイベントなど、様々なオブジェクトをイベントのストリームに変換できます。
次の例で、XMLファイルからイベントのストリームを変換する方法を示します。
XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance(); XMLInputStream stream = factory.newInputStream(new FileInputStream(name));
まず、XMLInputStreamFactory
の新しいインスタンスを作成し、次に、このファクトリを使用して、name
変数で参照されるXMLファイルから新しいXMLInputStream
を作成します。
次の例では、DOMツリーからストリームを作成する方法を示します。
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setValidating(false); dbf.setNamespaceAware(true); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(new java.io.File(file)); XMLInputStream stream = XMLInputStreamFactory.newInstance().newInputStream(doc);
XMLInputStream
オブジェクトの繰返し処理を終了した後は、このストリームに再度アクセスすることはできません。ただし再度ストリームを処理する必要がある場合、たとえば、ストリームを別のアプリケーションに送信したり、別の方法で再度繰返し処理したりする場合は、XMlInputStream
オブジェクトではなく、BufferedXMLInputStream
オブジェクトを使用できます。
バッファされたXML入力ストリームを作成するには、XMLInputStreamFactory
クラスのnewBufferedInputStream()
メソッドを使用します。以下に例を示します。
XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance(); BufferedXMLInputStream bufstream = factory.newBufferedInputStream(factory.newInputStream(new FileInputStream(name)));
BufferedXMLInputStream
オブジェクトのmark()
メソッドとreset()
メソッドにより、ストリームの特定のスポットをマークし、ストリームの処理を続け、マークしたスポットに戻るようにストリームをリセットできます。「バッファされたXML入力ストリームのマーキングとリセット」を参照してください。
XMLストリームのフィルタ処理とは、指定したタイプのオブジェクトのみの入ったストリームを作成することです。たとえば、開始要素、終了要素、およびXML要素の本文をマークアップする文字データのみの入ったストリームを作成できます。別の例では、指定した名前を持つ要素のみがストリームに出現するようにXMLストリームをフィルタ処理することもできます。
XMLストリームをフィルタ処理するには、XMLInputStreamFactory.newInputStream()
メソッドの2番目のパラメータとしてフィルタ・クラスを指定します。フィルタ・クラスに対するパラメータとしてXMLストリームに入れるイベントを指定します。次の例では、TypeFilter
クラスにより、結果のXMLストリームにXMLの開始要素と終了要素、および文字データのみを入れるように指定する方法を示します。
import weblogic.xml.stream.util.TypeFilter; XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance(); XMLInputStream stream = factory.newInputStream(new FileInputStream(name), new TypeFilter(XMLEvent.START_ELEMENT | XMLEvent.END_ELEMENT | XMLEvent.CHARACTER_DATA));
表B-2で、WebLogic XML Streaming APIに用意されているフィルタについて説明します。これらは、weblogic.xml.stream.util
パッケージの一部です。
表B-2 WebLogic XML Streaming APIによって提供されるフィルタ
フィルタの名前 | 説明 | 使用例 |
---|---|---|
TypeFilter |
TypeFilterは、入力として整数ビット・マスクを取ります。例に示すとおり、このビット・マスクを作成するには、値のOR (論理和)を取ります。 |
new TypeFilter (XMLEvent.START_ELEMENT | XMLEvent.END_ELEMENT | XMLEvent.CHARACTER_DATA) |
NameFilter |
XMLドキュメント内の要素の名前に基づいてXMLストリームをフィルタ処理します。 |
new NameFilter ("Book") |
NameSpaceFilter |
指定されたネームスペースURIに基づいてXMLストリームをフィルタ処理します。 |
new NameSpaceFilter ("http://namespace.org") |
NamespaceTypeFilter |
指定されたイベント・タイプとネームスペースURIに基づいてXMLストリームをフィルタ処理します。このフィルタは、 |
new NamespaceFilter ("http://namespace.org", XMLEvent.START_ELEMENT) この例は、すべての開始要素が指定されたネームスペースを持っているストリームを返します。 |
イベントのストリームが完成したら、次にXMLInputStream.next()
メソッドとXMLInputStream.hasNext()
メソッドを使用して、イベントのストリームを手順に沿って処理します。以下に例を示します。
while(stream.hasNext()) { XMLEvent event = stream.next(); System.out.print(event); }
XMLInputStream.next()
メソッドは、XMLEvent
タイプのオブジェクトを返します。XMLEvent
には、このイベントが、XMLドキュメントの開始、要素の終了、エンティティ参照などのどれであるかをさらに分類するサブインタフェースがあります。XMLEvent
インタフェースには、対応するフィールド、すなわち定数、ならびに実際のイベントを識別するために使用できるメソッドのセットも入っています。図B-1では、XMLEvent
インタフェースとそのサブインタフェースの階層を示します。
表B-3に、XMLストリームの解析時に特定のイベントを識別するために使用できるXMLEvent
クラスのサブクラスとフィールドをリストします。
表B-3 XMLEventクラスのサブクラスとフィールド
XMLEventサブクラス | サブクラスを識別するために使用されるXMLEventクラスのフィールド | サブクラスを識別するために使用されるメソッド | サブクラス・イベントの説明 |
---|---|---|---|
ChangePrefixMapping |
CHANGE_PREFIX_MAPPING |
isChangePrefixMapping |
接頭辞マッピングが古いネームスペースから新しいネームスペースに変更されたことを示します。 |
CharacterData |
CHARACTER_DATA |
isCharacterData |
返された |
Comment |
COMMENT |
isComment |
返された |
EndDocument |
END_DOCUMENT |
isEndDocument |
XMLドキュメントの終了を示します。 |
EndElement |
END_ELEMENT |
isEndElement |
XMLドキュメントの要素の終了を示します。 |
EndPrefixMapping |
END_PREFIX_MAPPING |
isEndPrefixMapping |
接頭辞マッピングがスコープの範囲外になったことを示します。 |
EntityReference |
ENTITY_REFERENCE |
isEntityReference |
返された |
ProcessingInstruction |
PROCESSING_INSTRUCTION |
isProcessingInstruction |
返された |
Space |
SPACE |
isSpace |
返された |
StartDocument |
START_DOCUMENT |
isStartDocument |
XMLドキュメントの開始を示します。 |
StartElement |
START_ELEMENT |
isStartElement |
XMLドキュメントの要素の開始を示します。 |
StartPrefixMapping |
START_PREFIX_MAPPING |
isStartPrefixMapping |
接頭辞マッピングがそのスコープを開始したことを示します。 |
次の例では、Java case
文を使用して、XMLInputStream.next()
メソッドにより返されたイベントのタイプを判別する方法を示します。簡単にするため、この例では、見つかったイベントをそのまま出力します。イベントをさらに処理する方法は、その後の節で示します。
switch(event.getType()) { case XMLEvent.START_ELEMENT: // Start of an element System.out.println ("Start Element\n"); break; case XMLEvent.END_ELEMENT: // End of an element System.out.println ("End Element\n"); break; case XMLEvent.PROCESSING_INSTRUCTION: // Processing Instruction System.out.println ("Processing instruction\n"); break; case XMLEvent.SPACE: // Whitespace System.out.println ("White space\n"); break; case XMLEvent.CHARACTER_DATA: // Character data System.out.println ("Character data\n"); break; case XMLEvent.COMMENT: // Comment System.out.println ("Comment\n"); break; case XMLEvent.START_DOCUMENT: // Start of the XML document System.out.println ("Start Document\n"); break; case XMLEvent.END_DOCUMENT: // End of the XML Document System.out.println ("End Document\n"); break; case XMLEvent.START_PREFIX_MAPPING: // The start of a prefix mapping scope System.out.println ("Start prefix mapping\n"); break; case XMLEvent.END_PREFIX_MAPPING: // The end of a prefix mapping scope System.out.println ("End prefix mapping\n"); break; case XMLEvent.CHANGE_PREFIX_MAPPING: // Prefix mapping has changed namespaces System.out.println ("Change prefix mapping\n"); break; case XMLEvent.ENTITY_REFERENCE: // An entity reference System.out.println ("Entity reference\n"); break; default: throw new XMLStreamException("Attempt to parse unknown event [" + event.getType() + "]"); }
XMLドキュメントの要素の属性を取得するには、まず、XMLInputStream.next()
メソッドにより返されたXMLEvent
オブジェクトをStartElement
オブジェクトにキャストする必要があります。
要素に属性がいくつあるかが分からないため、まず、属性のリスト全体を入れるAttributeIterator
オブジェクトを作成してから、属性がなくなるまでリストを繰返し処理します。次の例で、「ストリームの繰返し処理」に示したswitch
文のSTART_ELEMENT
caseの一部としてこれを行う方法を示します。
case XMLEvent.START_ELEMENT: StartElement startElement = (StartElement) event; System.out.print("<" + startElement.getName().getQualifiedName() ); AttributeIterator attributes = startElement.getAttributesAndNamespaces(); while(attributes.hasNext()){ Attribute attribute = attributes.next(); System.out.print(" " + attribute.getName().getQualifiedName() + "='" + attribute.getValue() + "'"); } System.out.print(">"); break;
この例では、まず、返されたXMLEvent
をStartElement
にキャストすることにより、StartElement
オブジェクトを作成します。次に、StartElement.getAttributesAndNamespaces()
メソッドを使用してAttributeIterator
オブジェクトを作成し、AttributeIterator.hasNext()
メソッドを使用して属性を繰返し処理します。各Attribute
について、Attributes.getName().getQualifiedName()
メソッドとAttribute.getValue()
メソッドを使用し、属性の名前と値を返します。
getNamespace()
メソッドやgetAttributes()
メソッドを使用すると、ネームスペースや属性のみを返すこともできます。
表B-4で、ストリームの特定の位置までスキップするために使用できるXMLInputStream
インタフェースのメソッドについて説明します。
表B-4 入力ストリームの位置決めのために使用されるメソッド
XMLInputStreamのメソッド | 説明 |
---|---|
skip() |
入力ストリームを次のストリーム・イベントに位置決めします。 注意: 次のイベントは、XMLファイル内の実際の要素であるとはかぎりません。コメントやホワイトスペースの場合もあります。 |
skip(int) |
入力ストリームをこのタイプの次のイベントに位置決めします。 イベント・タイプの例としては、 |
skip(XMLName) |
入力ストリームをこの名前の次のイベントに位置決めします。 |
skip(XMLName, int) |
入力ストリームをこの名前とタイプの次のイベントに位置決めします。 |
skipElement() |
次の要素にスキップします(現在の要素の下位要素にはスキップしません)。 |
peek() |
ストリームから実際には読み込まずに、次のイベントをチェックします。 |
次の例では、入力ストリームを繰返し処理する基本コードを修正し、XML要素の本文の文字データをスキップする方法を示します。
while(stream.hasNext()) { XMLEvent peek = stream.peek(); if (peek.getType() == XMLEvent.CHARACTER_DATA ) { stream.skip(); continue; } XMLEvent event = stream.next(); parse(event); }
この例は、XMLInputStream.peek()
メソッドを使用してストリーム上の次のイベントを判別する方法を示しています。イベントのタイプがXMLEvent.CHARACTER_DATA
である場合、そのイベントはスキップされ、次のイベントに進みます。
すべての下位要素も含め、次の要素のコピーを取得するには、XMLInputStream.getSubStream()
メソッドを使用します。getSubstream()
メソッドは、XMLInputStream
オブジェクトを返します。親ストリーム(またはgetSubStream()
を呼び出したストリーム)での位置は移動しません。親ストリームでは、getSubStream()
で取得した要素をスキップする場合、skipElement()
メソッドを使用します。
getSubStream()
メソッドは、検出されたSTART_ELEMENT
イベントとEND_ELEMENT
イベントの数を記録し、その数が等しくなると(すなわち、完全な次の要素が見つかると)停止して、結果のサブストリームをXMLInputStream
オブジェクトとして返します。
たとえば、XML Streaming APIを使用して以下のXMLドキュメントを解析するとします。ただし、<content>
タグと</content>
タグに囲まれたサブストリームのみを対象にします。
<book> <title>The History of the World</title> <author>Juliet Shackell</author> <publisher>CrazyDays Publishing</publisher> <content> <chapter title='Just a Speck of Dust'> <synopsis>The world as a speck of dust</synopsis> <para>Once the world was just a speck of dust...</para> </chapter> <chapter title='Life Appears'> <synopsis>Move over dust, here comes life.</synopsis> <para>Happily, the dust got a companion: life...</para> </chapter> </content> </book>
次のコード(抜粋)は、<content>
開始要素タグにスキップし、サブストリームを取得し、独立したComplexParse
オブジェクトを使用してそのサブストリームを解析する方法を示しています。
if (stream.skip( ElementFactory.createXMLName("content"))) { ComplexParse complexParse = new ComplexParse(); complexParse.parse(stream.getSubStream()); }
前のXMLドキュメントでこのメソッドを呼び出すと、以下の出力が得られます。
<content> <chapter title='Just a Speck of Dust'> <synopsis>The world as a speck of dust</synopsis> <para>Once the world was just a speck of dust...</para> </chapter> <chapter title='Life Appears'> <synopsis>Move over dust, here comes life.</synopsis> <para>Happily, the dust got a companion: life...</para> </chapter> </content>
BufferedXMLInputStream
オブジェクトを使用する場合、mark()
メソッドとreset()
メソッドにより、ストリームの特定のスポットをマークし、ストリームの処理を続けた後、マークしたスポットに戻るようにストリームをリセットできます。この2つのメソッドは、最初に繰返し処理をした後で、ストリームをさらに操作したい場合に便利です。
注意:
バッファされたストリームをマーキングせずに読み取った場合、直前に読み取ったものにアクセスすることはできません。つまり、ストリームはバッファされるだけであり、自動的にストリームを再読取りできることを意味するわけではありません。まずストリームをマークしておく必要があります。
次の例で、BufferedXMLInputStream
オブジェクトの一般的な使い方を示します。
XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance(); BufferedXMLInputStream bufstream = factory.newBufferedInputStream(factory.newInputStream(new FileInputStream(name))); // mark the start of the stream bufstream.mark(); // process it locally bufferedParse.parse(bufstream); // reset the stream to the mark bufstream.reset(); // send stream off to another application ComplexParse complexParse = new ComplexParse(); complexParse.parse(bufstream);
次の手順では、WebLogic XML Streaming APIにより新しいXMLドキュメントを生成する一般的手順について説明します。
最初の2つの手順は必須です。その後の手順は、XMLファイルをどのように生成するかに応じて実行します。
weblogic.xml.stream.*
クラスをインポートします。以下の節では、XML Streaming APIによりXMLドキュメントを生成する例を示します。
このプログラムでは、まず、PrintWriter
オブジェクトに基づいて出力ストリームを作成し、次に、その出力ストリームに要素を追加して、プログラムのコメントに説明されているように、単純なXML発注書を作成します。また、別のXMLファイルに基づく入力ストリームを出力ストリームに追加する方法も示します。
注意:
サンプルの後の節に、さらに詳しい説明があります。
package examples.xml.stream; import weblogic.xml.stream.XMLInputStream; import weblogic.xml.stream.XMLOutputStream; import weblogic.xml.stream.XMLInputStreamFactory; import weblogic.xml.stream.XMLName; import weblogic.xml.stream.XMLEvent; import weblogic.xml.stream.StartElement; import weblogic.xml.stream.EndElement; import weblogic.xml.stream.Attribute; import weblogic.xml.stream.ElementFactory; import weblogic.xml.stream.XMLStreamException; import weblogic.xml.stream.XMLOutputStreamFactory; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.PrintWriter; /** * Program that prints out a very simple purchase order that looks * like the following: * * <purchase_order> * <name>Juliet Shackell</name> * <item id="1234" quantity="2">Fabulous Chair</item> * <!-- this is a comment--> * <another_file> * This comes from another file called "another_file.xml" * </another_file> * </purchase_order> * * In the preceding XML file, the <another_file> element is actually another * XML file that is passed as an argument to the program, converted into an * XMLInputStream, then added to the output stream. */ public class PrintPurchaseOrder { /** * Helper method to get a handle on a stream. * Takes in a name and returns a stream. This * method uses the InputStreamFactory to create an * instance of an XMLInputStream * @param name The file to parse * @return XMLInputStream the stream to parse */ public XMLInputStream getInputStream(String name) throws XMLStreamException, FileNotFoundException { XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance(); XMLInputStream stream = factory.newInputStream(new FileInputStream(name)); return stream; } public static void main(String args[]) throws Exception { PrintPurchaseOrder printer = new PrintPurchaseOrder(); // // Create an output stream. // XMLOutputStreamFactory factory = XMLOutputStreamFactory.newInstance(); XMLOutputStream output = factory.newOutputStream(new PrintWriter(System.out,true)); // add the <purchase_order> root element output.add(ElementFactory.createStartElement("purchase_order")); output.add(ElementFactory.createCharacterData("\n")); // add the <name> element output.add(ElementFactory.createStartElement("name")); output.add(ElementFactory.createCharacterData("Juliet Shackell")); output.add(ElementFactory.createEndElement("name")); output.add(ElementFactory.createCharacterData("\n")); // add the <item> element along with the id and quantity attributes output.add(ElementFactory.createStartElement("item")); output.add(ElementFactory.createAttribute("id","1234")); output.add(ElementFactory.createAttribute("quantity","2")); output.add(ElementFactory.createCharacterData("Fabulous Chair")); output.add(ElementFactory.createEndElement("item")); output.add(ElementFactory.createCharacterData("\n")); // add a comment output.add("<!-- this is a comment-->"); output.add(ElementFactory.createCharacterData("\n")); // create an input stream from each XML file argument then add it to the output for (int i=0; i < args.length; i++) // // Get an input stream and add it to the output stream // output.add(printer.getInputStream(args[i])); // Finally, end the root "purchase_order" element output.add(ElementFactory.createEndElement("purchase_order")); output.add(ElementFactory.createCharacterData("\n")); // // Print the results to the screen // output.flush(); // Close the output streams output.close(); } }
上のプログラムは、次の出力を生成します。
<purchase_order> <name>Juliet Shackell</name> <item id="1234" quantity="2">Fabulous Chair</item> <!-- this is a comment--> <another_file> This is from another file. </another_file> </purchase_order>
WebLogic XML Streaming APIによりXMLドキュメントを生成する最初の手順の1つは、構築されるドキュメントを入れるための出力ストリームを作成することです。XML出力ストリームの作成方法は、入力ストリームの作成方法と似ています。まず、XMLOutputStreamFactory
のインスタンスを作成し、次にXMLOutputStreamFactory.newOutputStream()
メソッドで出力ストリームを作成します。以下に例を示します。
XMLOutputStreamFactory factory = XMLOutputStreamFactory.newInstance(); XMLOutputStream output = factory.newOutputStream(new PrintWriter(System.out,true));
次の例では、DOMツリーに基づいてXMLOutputStream
を作成する方法を示します。
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setValidating(false); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder().newDocument(); XMLOutputStream out = XMLOutputStreamFactory.newInstance().newOutputStream(doc);
XMLOutputStreamFactory.newOutputStream()
メソッドを使用して、以下の4つのJavaオブジェクトに基づく出力ストリームを作成できます。オブジェクトは、XMLドキュメントの最終形式を何にするか(オペレーティング・システム上のファイル、DOMツリーなど)に応じて決定します。
java.io.OutputStream
java.io.Writer
org.xml.sax.ContentHandler
org.w3c.dom.Document
出力ストリームに要素を追加するには、XMLOutputStream.add(XMLEvent)
メソッドを使用します。特定の要素を作成するには、ElementFactory
を使用します。
ElementFactory
インタフェースには、各タイプの要素を作成するためのメソッドがあります。一般的なフォーマットはElementFactory.create
XXX
()
です。XXX
は、createStartElement()
、createCharacterData()
などの特定の要素を表します。String
またはXMLName
のような名前を渡すことにより、大部分の要素を作成できます。
ヒント:
XMLOutputStream
はXMLを検証しません。
注意:
開始要素を作成するたびに、終了要素もどこかに明示的に作成する必要があります。同じ規則が開始ドキュメントの作成にも適用されます。
たとえば、次のような小さなXMLを作成するとします。
<name>Juliet Shackell</name>
出力ストリームにこの要素を追加するJavaコードは次のようになります。
output.add(ElementFactory.createStartElement("name")); output.add(ElementFactory.createCharacterData("Juliet Shackell")); output.add(ElementFactory.createEndElement("name")); output.add(ElementFactory.createCharacterData("\n"));
最後のcreateCharacterData()
メソッドは、出力ストリームに改行文字を追加します。この指定は必須ではありませんが、読みやすいXMLを作成するときに便利です。
作成した要素に属性を追加するには、XMLOutputStream.add(Attribute)
を使用します。特定の属性を作成するには、ElementFactory.createAttribute()
メソッドを使用します。
たとえば、次のような小さなXMLを作成するとします。
<item id="1234" quantity="2">Fabulous Chair</item>
出力ストリームにこの要素を追加するJavaコードは次のようになります。
output.add(ElementFactory.createStartElement("item")); output.add(ElementFactory.createAttribute("id","1234")); output.add(ElementFactory.createAttribute("quantity","2")); output.add(ElementFactory.createCharacterData("Fabulous Chair")); output.add(ElementFactory.createEndElement("item")); output.add(ElementFactory.createCharacterData("\n"));
注意:
要素への属性の追加は、開始要素を作成した後、対応する終了要素を作成する前に行ってください。そうしない場合、コードは正常にコンパイルされますが、プログラム実行時にエラーが発生します。たとえば、次のコードでは、<item>
要素が明示的に終了した後に、この要素に属性が追加されているので、エラーが返されます。
output.add(ElementFactory.createStartElement("item")); output.add(ElementFactory.createEndElement("item")); output.add(ElementFactory.createAttribute("id","1234")); output.add(ElementFactory.createAttribute("quantity","2")); output.add(ElementFactory.createCharacterData("Fabulous Chair")); output.add(ElementFactory.createCharacterData("\n"));
XML出力ストリームを作成する際、XMLファイルやDOMツリーのような既存のXMLドキュメントを出力ストリームに追加したいことがあります。これを行うには、まず、そのXMLドキュメントをXML入力ストリームに変換してから、XMLOutputStream.add(XMLInputStream)
メソッドを使用して出力ストリームに入力ストリームを追加します。
次の例では、まず、XMLファイルからXML入力ストリームを作成するgetInputStream()というメソッドを示し、その後、このメソッドを使用して作成された入力ストリームを出力プログラムに追加する方法を示します。
/** * Helper method to get a handle on a stream. * Takes in a name and returns a stream. This * method uses the InputStreamFactory to create an * instance of an XMLInputStream * @param name The file to parse * @return XMLInputStream the stream to parse */ public XMLInputStream getInputStream(String name) throws XMLStreamException, FileNotFoundException { XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance(); XMLInputStream stream = factory.newInputStream(new FileInputStream(name)); return stream; } .... // create an input stream from each XML file argument then add it to the output for (int i=0; i < args.length; i++) // // Get an input stream and add it to the output stream // output.add(printer.getInputStream(args[i]));
XML出力ストリームを作成元のオブジェクトに出力するには、XMLOutputStream.flush()
メソッドを使用します。たとえば、PrintWriter
オブジェクトからXML出力ストリームを作成した場合、そのストリームは、flush()
メソッドにより標準出力に出力されます。
注意:
DOMツリーに基づいてXMLOutputStreamに書き込む場合、DOMを操作するには、その前にflush()
メソッドを実行する必要があります。
次の例では、出力ストリームを出力する方法を示します。
// // Print the results to the screen // output.flush();