B WebLogic XML Streaming APIの使用(非推奨)

この付録では、WebLogic XML Streaming APIによりXMLドキュメントの解析と生成を行う方法について説明します。

ノート:

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の概要

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オブジェクトを作成するために使用されるファクトリ。

XMLInputStream

イベントの入力ストリームを入れるために使用されるインタフェース。

BufferedXMLInputStream

XMLInputStreamインタフェースでストリームのマーキングとリセットを行えるようにするための拡張。

XMLOutputStreamFactory

XMLドキュメント生成用のXMLOutputStreamオブジェクトを作成するために使用されるファクトリ。

XMLOutputStream

イベントを書き込むために使用されるインタフェース。

ElementFactory

このAPIで使用されるインタフェースのインスタンスを作成するためのユーティリティ。

XMLEvent

要素の開始、要素の終了など、XMLドキュメントでのすべてのタイプのイベントのための基本インタフェース。

StartElement

XMLEventサブ・インタフェースの最重要部。XMLドキュメントの開始要素に関する情報を取得するために使用されます。

AttributeIterator

要素の属性のセットを繰返し処理するために使用されるオブジェクト。

Attribute

要素の特定の属性を記述するオブジェクト。

WebLogic XML Streaming APIのJavadoc

以下のJavadocには、この章で説明したWebLogic XML Streaming API機能に加え、詳しく説明されていない機能に関するリファレンスが掲載されています。

XMLドキュメントの解析:一般的なステップ

以下の手順は、WebLogic XML Streaming APIによりXMLドキュメントの解析と操作を行う一般的なステップについて説明したものです。

最初の2つのステップは必須です。その後のステップは、XMLファイルをどのように処理するかに応じて実行します。

  1. weblogic.xml.stream.*クラスをインポートします。
  2. XMLファイル、DOMツリー、またはSAXイベントのセットからイベントのXMLストリームを取得します。XMLストリームをフィルタ処理することにより、特定のタイプのイベント、特定の要素の名前などのみを取得することもできます。「XML入力ストリームの取得」を参照してください
  3. ストリームを繰返し処理し、汎用XMLEventタイプを返します。「ストリームの繰返し処理」を参照してください
  4. 汎用XMLEventタイプのそれぞれについて、イベント・タイプを判別します。イベント・タイプには、XMLドキュメント、要素の終了、エンティティ参照などがあります。「特定のXMLEventタイプの判別」を参照してください
  5. 要素の属性を取得します。「要素の属性の取得」を参照してください
  6. イベント全体のスキップ、特定のイベントのスキップなどにより、ストリームを位置決めします。「ストリームの位置決め」を参照してください
  7. 要素の子を取得します。「サブストリームの取得」を参照してください
  8. ストリームをクローズします。「入力ストリームのクローズ」を参照してください

XMLドキュメント解析の例

以下の節では、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入力ストリームの取得

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);

バッファされたXML入力ストリームの取得

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ストリームをフィルタ処理することもできます。

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

XMLEvent.START_ELEMENTXMLEvent.END_ELEMENTなど、指定されたイベント・タイプに基づいてXMLストリームをフィルタ処理します。イベント・タイプの詳細なリストについては、「特定のXMLEventタイプの判別」を参照してください。

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ストリームをフィルタ処理します。このフィルタは、TypeFilterNameSpaceFilterの機能を結合したものです。

new NamespaceFilter ("http://namespace.org", XMLEvent.START_ELEMENT)

この例は、すべての開始要素が指定されたネームスペースを持っているストリームを返します。

カスタム・フィルタの作成

APIに入っているフィルタがニーズに合わない場合は、独自のフィルタを作成することもできます。

  1. ElementFilterインタフェースを実装し、accept(XMLEvent)というメソッドを持つクラスを作成します。このメソッドは、ストリームに特定のイベントを追加するかどうかをXMLInputStreamFactory.newInputStream()メソッドに通知します。以下に例を示します。
    package my.filters;
    
    import weblogic.xml.stream.XMLName;
    import weblogic.xml.stream.ElementFilter;
    import weblogic.xml.stream.events.NullEvent;
    
    public class SuperDooperFilter implements ElementFilter {
    
      protected String name;
    
      public SuperDooperFilter(String name)
      {
        this.name = name;
      }
    
      public boolean accept(XMLEvent e) {
        if (name.equals(e.getName().getLocalName()))
          return true;
        return false;
      }
    }
    
  2. XMLアプリケーションで、新しいフィルタ・クラスをインポートしていることを確認します。
    import my.filters.SuperDooperFilter
    
  3. newInputStream()メソッドの2番目のパラメータとしてフィルタを指定します。これは、XMLストリームに入れるイベントのタイプを、フィルタ・クラスが必要とするフォーマットでフィルタ・クラスに渡します。
    XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance();
    XMLInputStream stream = factory.newInputStream(new FileInputStream(name), 
                            new SuperDooperFilter(param));
    

ストリームの繰返し処理

イベントのストリームが完成したら、次にXMLInputStream.next()メソッドとXMLInputStream.hasNext()メソッドを使用して、イベントのストリームをステップに沿って処理します。以下に例を示します。

while(stream.hasNext()) {
  XMLEvent event = stream.next();
  System.out.print(event);
}

特定のXMLEventタイプの判別

XMLInputStream.next()メソッドは、XMLEventタイプのオブジェクトを返します。XMLEventには、このイベントが、XMLドキュメントの開始、要素の終了、エンティティ参照などのどれであるかをさらに分類するサブインタフェースがあります。XMLEventインタフェースには、対応するフィールド、すなわち定数、ならびに実際のイベントを識別するために使用できるメソッドのセットも入っています。図B-1では、XMLEventインタフェースとそのサブインタフェースの階層を示します。

図B-1 XMLEventインタフェースとそのサブインタフェースの階層

図B-1の説明が続きます
「図B-1 XMLEventインタフェースとそのサブインタフェースの階層」の説明

表B-3に、XMLストリームの解析時に特定のイベントを識別するために使用できるXMLEventクラスのサブクラスとフィールドをリストします。

表B-3 XMLEventクラスのサブクラスとフィールド

XMLEventサブクラス サブクラスを識別するために使用されるXMLEventクラスのフィールド サブクラスを識別するために使用されるメソッド サブクラス・イベントの説明

ChangePrefixMapping

CHANGE_PREFIX_MAPPING

isChangePrefixMapping

接頭辞マッピングが古いネームスペースから新しいネームスペースに変更されたことを示します。

CharacterData

CHARACTER_DATA

isCharacterData

返されたXMLEventオブジェクトに要素の本文からの文字データが入っていることを示します。

Comment

COMMENT

isComment

返されたXMLEventオブジェクトにXMLコメントが入っていることを示します。

EndDocument

END_DOCUMENT

isEndDocument

XMLドキュメントの終了を示します。

EndElement

END_ELEMENT

isEndElement

XMLドキュメントの要素の終了を示します。

EndPrefixMapping

END_PREFIX_MAPPING

isEndPrefixMapping

接頭辞マッピングがスコープの範囲外になったことを示します。

EntityReference

ENTITY_REFERENCE

isEntityReference

返されたXMLEventオブジェクトにエンティティ参照が入っていることを示します。

ProcessingInstruction

PROCESSING_INSTRUCTION

isProcessingInstruction

返されたXMLEventオブジェクトに処理指示が入っていることを示します。

Space

SPACE

isSpace

返されたXMLEventオブジェクトにホワイトスペースが入っていることを示します。

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;

この例では、まず、返されたXMLEventStartElementにキャストすることにより、StartElementオブジェクトを作成します。次に、StartElement.getAttributesAndNamespaces()メソッドを使用してAttributeIteratorオブジェクトを作成し、AttributeIterator.hasNext()メソッドを使用して属性を繰返し処理します。各Attributeについて、Attributes.getName().getQualifiedName()メソッドとAttribute.getValue()メソッドを使用し、属性の名前と値を返します。

getNamespace()メソッドやgetAttributes()メソッドを使用すると、ネームスペースや属性のみを返すこともできます。

ストリームの位置決め

表B-4で、ストリームの特定の位置までスキップするために使用できるXMLInputStreamインタフェースのメソッドについて説明します。

表B-4 入力ストリームの位置決めのために使用されるメソッド

XMLInputStreamのメソッド 説明
skip()

入力ストリームを次のストリーム・イベントに位置決めします。

ノート: 次のイベントは、XMLファイル内の実際の要素であるとはかぎりません。コメントやホワイトスペースの場合もあります。

skip(int)

入力ストリームをこのタイプの次のイベントに位置決めします。

イベント・タイプの例としては、XMLEvent.START_ELEMENTXMLEvent.END_DOCUMENTなどがあります。イベント・タイプの詳細なリストについては、「表B-3」を参照してください。

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>

バッファされたXML入力ストリームのマーキングとリセット

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);

入力ストリームのクローズ

プログラミング慣行として、XML入力ストリームでの作業終了時に入力ストリームを明示的にクローズします。入力ストリームをクローズするには、XMLInputStream.close()メソッドを使用します。以下に例を示します。

// close the input stream
input.close();

新しいXMLドキュメントの生成:一般的なステップ

次の手順では、WebLogic XML Streaming APIにより新しいXMLドキュメントを生成する一般的なステップについて説明します。

最初の2つのステップは必須です。その後のステップは、XMLファイルをどのように生成するかに応じて実行します。

  1. weblogic.xml.stream.*クラスをインポートします。
  2. XMLドキュメントを書き込むためのXML出力ストリームを作成します。「XML出力ストリームの作成」を参照してください
  3. XML出力ストリームにイベントを追加します。「出力ストリームへの要素の追加」を参照してください
  4. XML出力ストリームに属性を追加します。「出力ストリームの要素への属性の追加」を参照してください
  5. 出力ストリームに入力ストリームを追加します。「出力ストリームへの入力ストリームの追加」を参照してください
  6. 出力ストリームを出力します。「出力ストリームの出力」を参照してください
  7. 出力ストリームをクローズします。「出力ストリームのクローズ」を参照してください

XMLドキュメント生成の例

以下の節では、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>

XML出力ストリームの作成

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.createXXX()です。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();

出力ストリームのクローズ

プログラミング慣行として、XML出力ストリームでの作業終了時に出力ストリームを明示的にクローズします。出力ストリームをクローズするには、XMLOutputStream.close()メソッドを使用します。以下に例を示します。

// close the output stream
output.close();