ヘッダーをスキップ
Oracle® Fusion Middleware Oracle WebLogic Server XMLのプログラミング
11g リリース1 (10.3.5)
B55533-03
  ドキュメント・ライブラリへ移動
ライブラリ
製品リストへ移動
製品
目次へ移動
目次

前
 
次
 

4 Streaming API for XML (StAX)の使い方

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

Streaming API for XMLの概要

Java Community ProcessのJSR-173 (http://www.jcp.org/en/jsr/detail?id=173)で定義されているStreaming API for XML (StAX)を使用すると、XMLドキュメントを簡単かつ直感的に解析および生成できます。SAX APIと似ていますが、XMLドキュメントに対する手続き的なストリーム・ベースの処理が可能であり、SAXイベント・ハンドラを作成する必要はありません。SAXイベント・ハンドラで複雑なXMLドキュメントを扱うと、ハンドラ自体が複雑になる場合があります。つまり、StAXを利用すれば、SAXよりきめ細かく解析を制御できます。

SAXを使用してXMLドキュメントを解析する場合、プログラムでは、イベント発生時に解析をリスニングするイベント・リスナーを作成し、特定のイベントを請求するのではなくイベントに対して対応する必要があります。一方、StAXを使用する場合は、XMLドキュメントを手順の流れに沿って処理すること、特定のタイプのイベント(要素の開始など)を請求すること、要素の属性を繰返し処理すること、ドキュメントの先頭をスキップすること、任意の時点で処理を停止すること、特定の要素の下位要素を取得すること、指定どおりに要素をフィルタ処理することができます。イベントに対応するのではなく、イベントを請求するので、StAXを使用する方法は、プル解析と呼ばれることもあります。

StAXには、カーソルAPIイベント・イテレータAPIという2つのAPIがあり、どちらでもXMLを読み書きできます。以下の節では、各APIおよびそれぞれの利点について説明します。

カーソルAPIの説明

カーソルAPIの基本機能は、できる限り簡単かつ効率的にXMLを解析および生成できるようにするためのものです。StAXの2つのAPIのうち、ほとんどのプログラマが使用すると思われるのは、こちらの方です。

カーソルAPIは、開始要素、コメント、属性などの一連のイベントを、発生していないものも含めて繰返し処理します。カーソルAPIには、XML解析用のXMLStreamReaderとXML生成用のXMLStreamWriterという2つの主要なインタフェースがあります。

XMLStreamReaderインタフェース

カーソルAPIは、XMLStreamReaderインタフェースを使用して仮想カーソルをXMLドキュメント上に移動し、hasNext()next()getEventType()、およびgetText()などのメソッドを呼び出してデータおよび基底の状態にアクセスできるようにします。XMLStreamReaderインタフェースでは、XMLに対して読取り専用の前方アクセスのみが可能です。

XMLStreamReaderの新しいインスタンスを作成するには、XMLInputFactoryクラスを使用します。新しいリーダー を取得すると、様々なプロパティを設定できます。詳細は、「XMLInputFactoryインタフェース用に定義されたプロパティ」を参照してください。

XMLStreamReaderインタフェースのnext()メソッドを使用してXMLを解析すると、リーダーは次の解析イベントを取得し、読み込んだイベントの種類を識別する整数を返します。解析イベントは、XML宣言、開始要素タグ、終了要素タグ、ホワイトスペース、コメント、処理手順などのXMLドキュメントの各セクションに対応します。XMLStreamConstantインタフェースは、next()メソッドによって返された整数に対応するイベントを指定します。XMLStreamReadergetEventType()メソッドを使用して、イベントの種類を判別することもできます。

XMLStreamReaderインタフェースには、XMLドキュメントの特定のデータを取得するための様々なメソッドがあります。そのメソッドの一部を次に示します。

  • getLocalName() - 現在のイベントのローカル名を返します。

  • getPrefix() - 現在のイベントの接頭辞を返します。

  • getAttributeXXX() - 現在の属性イベントに関する情報を返す一連のメソッドです。

  • getNamespaceXXX() - 現在のネームスペース・イベントに関する情報を返す一連のメソッドです。

  • getTextXXX() - 現在のテキスト・イベントに関する情報を返す一連のメソッドです。

  • getPIData() - 現在の処理手順イベントのデータ・セクションを返します。

有効なメソッドは、イベントの種類ごとに決まっています。無効なイベントの種類でメソッドを呼び出そうとすると、StAXプロセッサからjava.lang.IllegalStateExceptionが送出されます。たとえば、ネームスペース・イベントでgetAttributeXXX()メソッドを呼び出すとエラーになります。イベントの完全なリストとそのイベントで有効なXMLStreamReaderメソッドについては、http://www.jcp.org/en/jsr/detail?id=173にあるStAX仕様を参照してください。

XMLStreamWriterインタフェース

カーソルAPIは、XMLStreamWriterインタフェースを使用して、XMLの生成方法を指定します。

XMLStreamWriterの新しいインスタンスを作成するには、XMLOutputFactoryクラスを使用します。新しいライターを取得すると、ネームスペースおよび接頭辞を修正するためのプロパティを設定できます。詳細は、「XMLOutputFactoryインタフェース用に定義されたプロパティ」を参照してください。

XMLStreamWriterインタフェースには、XMLドキュメントの標準的な部分に書込みを行う一連のwriteXXX()メソッドが定義されています。以下に、そのメソッドを示します。

  • writeStartElement()

  • writeEndDocument()

  • writeAttribute()

  • writeNamespace()

  • writeCData()

属性とネームスペースを含むXMLドキュメントの各部分は、これらのメソッドによって明示的に書き込まれます。

キャッシュされたデータを出力に書き込むにはflush()メソッド、ライターを閉じてリソースを解放するにはclose()メソッドを使用します。

XMLStreamWriterは、XMLの生成時に、生成されたドキュメントが整形式かどうかをチェックしません。整形式のXMLドキュメントを作成するのは、プログラマの役目です。特殊文字&<、および>を出力するには、writeCharacters()メソッドを使用します。

イベント・イテレータAPIの説明

イベント・イテレータAPIは、カーソルAPIのすぐ上のレイヤーです。パイプライニングの拡張および促進を簡単に行うことができます。パイプライニングとは、複数のXML間の変換のことです。イベント・イテレータAPIを使用すると、パイプラインの各ステージでXMLをデシリアライズおよびシリアライズする必要はなくなり、パイプラインの両端でのみnextEvent()などのAPIメソッドを使用して中間ステージで通信します。イベント・イテレータAPIには、XML解析用のXMLEventReaderとXML生成用のXMLEventWriterという2つの主要なインタフェースがあります。

カーソルAPIがStAXで最も頻繁に使用されるAPIなので、このセクションではイベント・イテレータAPIの詳細な使い方については例を挙げる他には説明しません。このAPIの詳細な使い方については、StAX仕様(http://www.jcp.org/en/jsr/detail?id=173)を参照してください。

次の例では、StAXのXMLEventReaderインタフェースを使用してXMLドキュメントを解析する単純なプログラムを示します。このプログラムは、XMLファイルを表す1つのパラメータを取り、それを使用してXMLEventReaderオブジェクトを作成します。次に、リーダーを使用して、イベントのストリームを繰返し処理して出力します。

package examples.event;

import java.io.FileReader;
import javax.xml.stream.*;
import javax.xml.stream.events.*;
import javax.xml.stream.util.*;
import javax.xml.namespace.QName;

/**
 * A simple example to iterate over events
 *
 * @author Copyright (c) 2002 by BEA Systems. All Rights Reserved.
 */

public class Parse {
  private static String filename = null;
  private static void printUsage() {
    System.out.println("usage: java examples.event.Parse <xmlfile>");
  }

  public static void main(String[] args) throws Exception {
    try {
      filename = args[0];
    } catch (ArrayIndexOutOfBoundsException aioobe){
      printUsage();
      System.exit(0);
    }

    XMLInputFactory factory = XMLInputFactory.newInstance();
    XMLEventReader r =
      factory.createXMLEventReader(new FileReader(filename));
    while(r.hasNext()) {
      XMLEvent e = r.nextEvent();
      System.out.println("ID:"+e.hashCode()+"["+e+"]");
    }
  }
}

StAXのメイン・インタフェースとクラス

表4-1で、Streaming API for XMLの主なインタフェースとクラスについて説明します。

表4-1 Streaming API for XMLの主なインタフェースとクラス

インタフェースまたはクラス カーソルAPI用/イベント・イテレータAPI用 説明
XMLInputFactory class

両方

XMLStreamReaderまたはXMLEventReaderインスタンスの作成に使用するファクトリ・クラス。

XMLOutputFactory class

両方

XMLStreamWriterまたはXMLEventWriterインスタンスの作成に使用するファクトリ・クラス。

XMLEventFactory class

イベント・イテレータ

XMLEventインスタンスの作成に使用するファクトリ・クラス。

XMLStreamReader interface

カーソル

XMLドキュメントの解析に使用するインタフェース。次のイベントを参照および取得し、それ以降のイベントがあるかどうかをチェックできます。

XMLStreamWriter interface

カーソル

XMLドキュメントの生成に使用するインタフェース。開始要素や属性など、XMLドキュメントの特定の部分を生成する一連のwriteXXX()メソッドを利用できます。

XMLEventReader interface

イベント・イテレータ

XMLイベントの解析に使用するインタフェース。次のイベントを参照および取得し、それ以降のイベントがあるかどうかをチェックできます。

XMLEventWriter interface

イベント・イテレータ

XMLの生成に使用するインタフェース。add()メソッドを使用して出力ストリームにXMLEventsを追加します。

XMLEvent

イベント・イテレータ

イベントを処理する基本インタフェース。StartElementAttributeなど、XMLEventから拡張された特定の全XMLイベント。

XMLStreamException exception

両方

整形式のXMLドキュメント構造の欠陥など、予期しない処理エラーに関する基底の例外。


XMLStreamReaderインタフェースによるXMLの解析:一般的な手順

以下の手順は、StAXカーソルAPIのXMLStreamReaderインタフェースによりXMLドキュメントの解析を行う一般的手順について説明したものです。この手順では、「StAXを使用したXML解析の例」で示すサンプル・コードを用います。

  1. javax.xml.stream.*クラスをインポートします。

  2. 次のコードの抜粋で示すように、XMLInputFactory.newInstance()メソッドを使用してXMLInputFactoryをインスタンス化します。

    XMLInputFactory xmlif = XMLInputFactory.newInstance();
    

    設定可能なプロパティのリストについては、「XMLInputFactoryインタフェース用に定義されたプロパティ」を参照してください。

  3. XMLドキュメントを基に、XMLInputFactory.createXMLStreamReader()メソッドを使用してXMLStreamReaderオブジェクトをインスタンス化します。

    詳細は、「XMLStreamReaderオブジェクトの取得」を参照してください。

  4. 次のコードの抜粋で示すように、hasNext()メソッドとnext()メソッドで各XMLイベントを順番に処理してXMLドキュメントを解析します。

    while(xmlr.hasNext()){
          printEvent(xmlr);
          xmlr.next();
    

    この例では、xmlrXMLStreamReaderインスタンスに当たり、ローカル・メソッドprintEvent() (StAX APIの一部ではありません)が、次の手順に示すように特定のイベント・タイプを判別します。

  5. XMLドキュメントの解析中に、現在の特定のイベント・タイプを判別し、それに対応した処理を行います。イベント・タイプには、XMLドキュメントの開始と終了、XML要素の開始と終了、コメント、エンティティ参照などがあります。

    「特定のXMLイベント・タイプの判別」を参照してください。

  6. 現在のイベント・タイプが開始要素または終了要素の場合、必要に応じてその属性を取得します。

    「要素の属性の取得」を参照してください。

  7. 現在のイベント・タイプが開始要素または終了要素の場合、必要に応じてそのネームスペースを取得します。

    「要素のネームスペースの取得」参照してください。

  8. 現在のイベント・タイプにCDATAやコメントなどのテキスト・データが含まれる場合、必要に応じて実際のデータを取得します。

    「テキスト・データの取得」を参照してください。

  9. 必要に応じて、行番号や列番号など、現在のイベントの場所の情報を取得します。

    「場所の情報の取得」を参照してください。

  10. ストリームをクローズします。

    「入力ストリームのクローズ」を参照してください。

StAXを使用したXML解析の例

次の例では、StAXのXMLStreamReaderインタフェースを使用してXMLドキュメントを解析する単純なプログラムを示します。

このプログラムは、XMLファイルを表す1つのパラメータを取り、それを使用してXMLStreamReaderオブジェクトを作成します。次に、リーダーを使用してイベントのストリームを繰返し処理し、XML要素の開始、要素の属性のリスト、処理手順など、各イベントのタイプを判別します。このサンプル・プログラムは、内部メソッドを使用して、適切な場合は属性およびネームスペースのリストを出力し、これらのイベントに関する情報を出力します。

太字のコードは、以降の節で説明します。

package examples.basic;

import java.io.FileReader;
import java.util.Iterator;
import javax.xml.stream.*; 
import javax.xml.namespace.QName;

/**
 * This is a simple parsing example that illustrates
 * the XMLStreamReader class.
 *
 * @author Copyright (c) 2003 by BEA Systems. All Rights Reserved.
 */

public class Parse {
  private static String filename = null;
  private static void printUsage() {
    System.out.println("usage: java examples.basic.Parse <xmlfile>");
  }

  public static void main(String[] args) throws Exception {
    try {
      filename = args[0];
    } catch (ArrayIndexOutOfBoundsException aioobe){
      printUsage();
      System.exit(0);
    }

    //
    // Get an input factory
    //
    XMLInputFactory xmlif = XMLInputFactory.newInstance(); 
    System.out.println("FACTORY: " + xmlif); 

    //
    // Instantiate a reader
    //
    XMLStreamReader xmlr = xmlif.createXMLStreamReader(new FileReader(filename)); 
    System.out.println("READER:  " + xmlr + "\n");

    //
    // Parse the XML
    //
    while(xmlr.hasNext()){ 
      printEvent(xmlr); 
      xmlr.next(); 
    } 

    //
    // Close the reader
    //
    xmlr.close(); 

  }

  private static void printEvent(XMLStreamReader xmlr) {

    System.out.print("EVENT:["+xmlr.getLocation().getLineNumber()+"]["+ 
                     xmlr.getLocation().getColumnNumber()+"] "); 

    System.out.print(" [");
    switch (xmlr.getEventType()) { 

    case XMLStreamConstants.START_ELEMENT: 
      System.out.print("<"); 
      printName(xmlr); 
      printNamespaces(xmlr); 
      printAttributes(xmlr); 
      System.out.print(">"); 
      break; 
    case XMLStreamConstants.END_ELEMENT: 
      System.out.print("</"); 
      printName(xmlr); 
      System.out.print(">"); 
      break; 
    case XMLStreamConstants.SPACE: 
    case XMLStreamConstants.CHARACTERS: 
      int start = xmlr.getTextStart(); 
      int length = xmlr.getTextLength(); 
      System.out.print(new String(xmlr.getTextCharacters(), 
                                  start, 
                                  length)); 
      break; 

    case XMLStreamConstants.PROCESSING_INSTRUCTION: 
      System.out.print("<?"); 
      if (xmlr.hasText()) 
        System.out.print(xmlr.getText()); 
      System.out.print("?>"); 
      break; 

    case XMLStreamConstants.CDATA: 
      System.out.print("<![CDATA["); 
      start = xmlr.getTextStart(); 
      length = xmlr.getTextLength(); 
      System.out.print(new String(xmlr.getTextCharacters(), 
                                  start, 
                                  length)); 
      System.out.print("]]>"); 
      break; 

    case XMLStreamConstants.COMMENT: 
      System.out.print("<!--"); 
      if (xmlr.hasText()) 
        System.out.print(xmlr.getText()); 
      System.out.print("-->"); 
      break; 

    case XMLStreamConstants.ENTITY_REFERENCE: 
      System.out.print(xmlr.getLocalName()+"="); 
      if (xmlr.hasText()) 
        System.out.print("["+xmlr.getText()+"]"); 
      break; 

    case XMLStreamConstants.START_DOCUMENT: 
      System.out.print("<?xml"); 
      System.out.print(" version='"+xmlr.getVersion()+"'"); 
      System.out.print(" encoding='"+xmlr.getCharacterEncodingScheme()+"'"); 
      if (xmlr.isStandalone()) 
        System.out.print(" standalone='yes'"); 
      else 
        System.out.print(" standalone='no'"); 
      System.out.print("?>"); 
      break; 

    }
    System.out.println("]");
  }

  private static void printName(XMLStreamReader xmlr){
    if(xmlr.hasName()){ 
      String prefix = xmlr.getPrefix(); 
      String uri = xmlr.getNamespaceURI(); 
      String localName = xmlr.getLocalName(); 
      printName(prefix,uri,localName);
    }
  }

  private static void printName(String prefix,
                                String uri,
                                String localName) {
    if (uri != null && !("".equals(uri)) ) System.out.print("['"+uri+"']:");
    if (prefix != null) System.out.print(prefix+":");
    if (localName != null) System.out.print(localName);
  }

  private static void printAttributes(XMLStreamReader xmlr){
    for (int i=0; i < xmlr.getAttributeCount(); i++) { 
      printAttribute(xmlr,i); 
    }
  }

  private static void printAttribute(XMLStreamReader xmlr, int index) {
    String prefix = xmlr.getAttributePrefix(index); 
    String namespace = xmlr.getAttributeNamespace(index); 
    String localName = xmlr.getAttributeLocalName(index); 
    String value = xmlr.getAttributeValue(index); 
    System.out.print(" ");
    printName(prefix,namespace,localName);
    System.out.print("='"+value+"'");
  }

  private static void printNamespaces(XMLStreamReader xmlr){
    for (int i=0; i < xmlr.getNamespaceCount(); i++) { 
      printNamespace(xmlr,i); 
    }
  }

  private static void printNamespace(XMLStreamReader xmlr, int index) {
    String prefix = xmlr.getNamespacePrefix(index); 
    String uri = xmlr.getNamespaceURI(index); 
    System.out.print(" ");
    if (prefix == null)
      System.out.print("xmlns='"+uri+"'");
    else
      System.out.print("xmlns:"+prefix+"='"+uri+"'");
  }
}

XMLStreamReaderオブジェクトの取得

次のコードの抜粋で示すように、XMLInputFactory.createXMLStreamReader()メソッドを使用し、XMLドキュメントに基づいてXMLStreamReaderオブジェクトをインスタンス化します。

XMLStreamReader xmlr = xmlif.createXMLStreamReader(new FileReader(filename));

この例では、xmlifXMLInputFactoryインスタンスに当たります。

createXMLStreamReader()メソッドの様々なシグネチャにより、以下のXMLドキュメント・フォーマットをパラメータとして扱うことができます。

  • java.io.InputStream

  • java.io.Reader (例で示します)

  • javax.xml.transform.Source (JAXP API http://java.sun.com/xml/で指定されています)

特定のXMLイベント・タイプの判別

XMLドキュメントの解析中に特定のイベント・タイプを判別するには、XMLStreamReader.next()メソッドまたはXMLStreamReader.getEventType()メソッドを使用します。next()メソッドは、次のイベントを読み込んで、そのイベント・タイプを示す整数を返し、getEventType()メソッドは、現在のイベント・タイプを示す整数を単純に返します。XMLStreamReaderXMLStreamConstants上位インタフェースには、以下のリストに示すイベント・タイプ定数が定義されています。

  • XMLStreamConstants.ATTRIBUTE

  • XMLStreamConstants.CDATA

  • XMLStreamConstants.CHARACTERS

  • XMLStreamConstants.COMMENT

  • XMLStreamConstants.DTD

  • XMLStreamConstants.END_DOCUMENT

  • XMLStreamConstants.END_ELEMENT

  • XMLStreamConstants.ENTITY_DECLARATION

  • XMLStreamConstants.ENTITY_REFERENCE

  • XMLStreamConstants.NAMESPACE

  • XMLStreamConstants.NOTATION_DECLARATION

  • XMLStreamConstants.PROCESSING_INSTRUCTION

  • XMLStreamConstants.SPACE

  • XMLStreamConstants.START_DOCUMENT

  • XMLStreamConstants.START_ELEMENT

次の例では、Java case文を使用して、XMLStreamReader.next()メソッドから返されたイベントのタイプを判別する方法を示します。この例では、XMLStreamReader.getEventType()メソッドを使用して、next()メソッドから返された整数値を基に現在のイベント・タイプを判別します。簡単にするため、この例では、見つかったイベントをそのまま出力します。イベントをさらに処理する方法は、その後の節で示します。

switch (xmlr.getEventType()) {

case XMLStreamConstants.START_ELEMENT:
  System.out.print("Start Element\n");
  break;

case XMLStreamConstants.END_ELEMENT:
  System.out.print("End Element\n");
  break;

case XMLStreamConstants.SPACE:
  System.out.print("Space\n");
  break;

case XMLStreamConstants.CHARACTERS:
  System.out.print("Characters\n");
  break;

case XMLStreamConstants.PROCESSING_INSTRUCTION:
  System.out.print("Processing Instrcutions\n");
  break;

case XMLStreamConstants.CDATA:
  System.out.print("CDATA\n");
  break;

case XMLStreamConstants.COMMENT:
  System.out.print("Comment\n");
  break;

case XMLStreamConstants.DTD:
  System.out.print("DTD\n");
  break;

case XMLStreamConstants.ENTITY_REFERENCE:
  System.out.print("Entity Reference\n");
  break;

case XMLStreamConstants.ENTITY_DECLARATION:
  System.out.print("Entity Declaration\n");
  break;

case XMLStreamConstants.START_DOCUMENT:
  System.out.print("Start Document\n");
  break;

case XMLStreamConstants.END_DOCUMENT:
  System.out.print("End Document\n");
  break;

}

完全な要素名の取得

完全な要素名には、接頭辞、ネームスペースURI、ローカル名が含まれます。現在のイベントが開始要素または終了要素であることを判別したら、XMLStreamReaderインタフェースのgetPrefix()メソッド、getNamespaceURI()メソッド、およびgetLocalName()メソッドをそれぞれ使用して、この情報を取得します。

たとえば、サンプル・プログラムで、開始イベント要素のcase文が次のようになっているとします。

case XMLStreamConstants.START_ELEMENT:

  System.out.print("<");
  printName(xmlr);
  printNamespaces(xmlr);
  printAttributes(xmlr);
  System.out.print(">");
  break;

注意:

printNamespaces()メソッドとprintAttributes()メソッドについては、別の節で説明します。

2つのprintName()ローカル・メソッドは、次のようにgetXXX()メソッドを使用できます。

private static void printName(XMLStreamReader xmlr){
  if(xmlr.hasName()){
    String prefix = xmlr.getPrefix();
    String uri = xmlr.getNamespaceURI();
    String localName = xmlr.getLocalName();
    printName(prefix,uri,localName);
  }
}

private static void printName(String prefix,
                              String uri,
                              String localName) {
  if (uri != null && !("".equals(uri)) ) System.out.print("['"+uri+"']:");
  if (prefix != null) System.out.print(prefix+":");
  if (localName != null) System.out.print(localName);
}

要素の属性の取得

現在のイベントが開始要素、終了要素、または属性であることを判別したら、XMLStreamReaderインタフェースのgetAttributeXXX()メソッドを使用して、属性とその値のリストを取得します。


注意:

getAttributeXXX()メソッドを使用できるのは、開始要素、終了要素、属性イベントに対してのみです。それ以外のタイプのイベントでこのメソッドを実行しようとすると、java.lang.IllegalStateExceptionが送出されます。

getAttributeCount()メソッドを使用すると、現在の要素の属性数を取得し、属性のリストに対して反復処理を行うループでその属性数を使用することができます。メソッドは、ネームスペースをこの数には含みません。追加のgetAttributeXXX()メソッドは、特定の属性の接頭辞、ネームスペースURI、ローカル名、および値を返します。

たとえば、サンプル・プログラムで、開始イベント要素のcase文が次のようになっているとします。

case XMLStreamConstants.START_ELEMENT:

  System.out.print("<");
  printName(xmlr);
  printNamespaces(xmlr);
  printAttributes(xmlr);
  System.out.print(">");
  break;

注意:

printName()メソッドとprintNamespaces()メソッドについては、別の節で説明します。

次のローカル・メソッドprintAttributes()では、属性のリストに対して反復処理を行う方法を示します。属性索引はゼロベースなので、forループは0から始まります。

private static void printAttributes(XMLStreamReader xmlr){

  for (int i=0; i < xmlr.getAttributeCount(); i++) {
    printAttribute(xmlr,i);
  }
}

次のローカル・メソッドprintAttribute()では、特定の属性の全情報を出力する方法を示します。

private static void printAttribute(XMLStreamReader xmlr, int index) {
  String prefix = xmlr.getAttributePrefix(index);
  String namespace = xmlr.getAttributeNamespace(index);
  String localName = xmlr.getAttributeLocalName(index);
  String value = xmlr.getAttributeValue(index);
  System.out.print(" ");
  printName(prefix,namespace,localName);
  System.out.print("='"+value+"'");
}

printName()メソッドについては、「完全な要素名の取得」で説明しています。

要素のネームスペースの取得

現在のイベントが開始要素、終了要素、またはネームスペースであることを判別したら、XMLStreamReaderインタフェースのgetNamespaceXXX()メソッドを使用して、イベント用に宣言されたネームスペースのリストを取得します。


注意:

getNamespaceXXX()メソッドを使用できるのは、開始要素、終了要素、ネームスペース・イベントに対してのみです。それ以外のタイプのイベントでこのメソッドを実行しようとすると、java.lang.IllegalStateExceptionが送出されます。

getNamespaceCount()メソッドを使用すると、現在のイベント用に宣言されているネームスペースの数を返し、そのリストに対して反復処理を行うループでそのネームスペース数を使用することができます。現在のイベントが終了要素の場合、この数は、スコープ外になるネームスペースの数を示します。追加のgetNamespaceXXX()メソッドは、特定のネームスペースの接頭辞とネームスペースURIを返します。

たとえば、サンプル・プログラムで、開始イベント要素のcase文が次のようになっているとします。

case XMLStreamConstants.START_ELEMENT:

  System.out.print("<");
  printName(xmlr);
  printNamespaces(xmlr);
  printAttributes(xmlr);
  System.out.print(">");
  break;

注意:

printName()メソッドとprintAttributes()メソッドについては、別の節で説明します。

次のローカル・メソッドprintNamespaces()では、開始要素のネームスペースのリストに対して反復処理を行う方法を示します。ネームスペース索引はゼロベースなので、forループは0から始まります。

private static void printNamespaces(XMLStreamReader xmlr){
  for (int i=0; i < xmlr.getNamespaceCount(); i++) {
    printNamespace(xmlr,i);
  }
}

次のローカル・メソッドprintNamespace()では、特定のネームスペースの全情報を出力する方法を示します。

private static void printNamespace(XMLStreamReader xmlr, int index) {
  String prefix = xmlr.getNamespacePrefix(index);
  String uri = xmlr.getNamespaceURI(index);
  System.out.print(" ");
  if (prefix == null)
    System.out.print("xmlns='"+uri+"'");
  else
    System.out.print("xmlns:"+prefix+"='"+uri+"'");
}

デフォルトのネームスペース宣言の場合、getNamespacePrefix()メソッドはnullを返します。

テキスト・データの取得

XMLStreamReaderインタフェースには、コメントやCDATAなどのイベントからテキスト・データを取得するための様々なgetTextXXX()メソッドが用意されています。

getTextStart()メソッドを使用して、現在のテキスト・イベントの最初の文字が格納されているテキスト文字配列内にオフセットを取得します。getTextLength()メソッドを使用して、テキスト文字配列内の文字列の長さを取得します。最後に、getTextCharacters()メソッドを使用して、現在のイベントのこの文字配列を返します。文字配列には、現在のイベントのみに関するテキスト情報が含まれています。next()メソッドを呼び出すと、入力ストリームの次のイベントがすぐに読み込まれ、文字配列に新しい情報が格納されます。

次の例では、CDATAイベントのテキスト・データを出力する方法を示します。

case XMLStreamConstants.CDATA:
  System.out.print("<![CDATA[");
  start = xmlr.getTextStart();
  length = xmlr.getTextLength();
  System.out.print(new String(xmlr.getTextCharacters(),
                              start,
                              length));
  System.out.print("]]>");
  break;

文字イベントに実際にテキストがあることを最初にチェックする場合は、次の例に示すようにhasText()メソッドを使用します。

case XMLStreamConstants.COMMENT:
  System.out.print("<!--");
  if (xmlr.hasText())
    System.out.print(xmlr.getText());
  System.out.print("-->");
  break;

場所の情報の取得

StAX APIのLocationインタフェースでは、解析対象のXMLのパブリックIDやシステムIDとともに、行番号や列番号などイベントに関する場所の情報を取得するためのメソッドを利用できます。次の例に示すように、XMLStreamReaderインタフェースのgetLocation()メソッドを使用して、現在のイベントのLocationオブジェクトを返します。

System.out.print("EVENT:["+xmlr.getLocation().getLineNumber()+"]["+
                     xmlr.getLocation().getColumnNumber()+"] ");

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

プログラミング慣行として、作業終了時にXMLStreamReaderを明示的にクローズしてリソースを解放します。リーダーをクローズするには、XMLStreamReader.close()メソッドを使用します。以下に例を示します。

//
// Close the reader
//
xmlr.close();

XMLStreamWriterインタフェースによるXMLの生成:一般的な手順

以下の手順は、StAXカーソルAPIのXMLStreamWriterインタフェースにより、新しいXMLドキュメントの生成を行う一般的手順について説明したものです。

  1. javax.xml.stream.*クラスをインポートします。

  2. XMLOutputFactory.newInstance()メソッドを使用してXMLOutputFactoryをインスタンス化します。次に例を示します。

    XMLOutputFactory xmlof = XMLOutputFactory.newInstance();
    

    設定可能なプロパティのリストについては、「XMLOutputFactoryインタフェース用に定義されたプロパティ」を参照してください。

  3. XMLOutputFactory.createXMLStreamWriter()メソッドを使用して、XMLを含むファイルまたはオブジェクトの名前を渡し、XMLStreamWriterオブジェクトをインスタンス化します。

    詳細は、「XMLStreamWriterオブジェクトの取得」を参照してください。

  4. XML宣言を出力に追加します。「出力ストリームへのXML宣言の追加」を参照してください。

  5. 開始要素、コメント、文字などの標準XMLオブジェクトを出力に追加します。「出力ストリームへの標準XMLイベントの追加」を参照してください。

  6. 属性とネームスペース宣言を開始要素に追加します。「属性とネームスペース宣言の開始要素への追加」を参照してください。

  7. 出力ストリームをクローズします。「出力ストリームのクローズ」を参照してください。

StAXを使用したXML生成の例

次の例では、StAXのXMLStreamWriterインタフェースを使用してXMLドキュメントを生成する単純なプログラムを示します。

このサンプル・プログラムではまず、カレント・ディレクトリにあるoutFile.xmlファイルに出力が書き込まれるように指定して、XMLStreamWriterのインスタンスを作成します。次に、様々なwriteXXX()メソッドを使用して、次のようなXMLファイルをビルドします。

<?xml version='1.0' encoding='utf-8'?>

<!--this is a comment-->
<person xmlns:one="http://namespaceOne" gender="f">
    <one:name hair="pigtails" freckles="yes">Pippi Longstocking</one:name>
</person>

XMLStreamWriterインタフェースは、XMLドキュメントが整形式かどうかをチェックしません。各開始要素と終了要素が対応しているかどうかなどを確認するのは、プログラマの役目です。この例では、writeCharacters("\n")メソッドを使用して、テキスト・ファイルへの書込み時にXMLを読みやすくするために新しい行を出力に追加する方法についても示します。

太字のコードは、以降の節で説明します。

package examples.basic;

import java.io.FileOutputStream;
import java.util.Iterator;
import javax.xml.stream.*; 
import javax.xml.namespace.QName;

/**
 * This is a simple example that illustrates how to use the
 * the XMLStreamWriter class to generate XML.
 *
 * The generated XML file looks like this:
 *
 *   <?xml version='1.0' encoding='utf-8'?>
 *
 *   <!--this is a comment-->
 *   <person xmlns:one="http://namespaceOne" gender="f">
 *       <one:name hair="pigtails" freckles="yes">Pippi Longstocking</one:name>
 *   </person>
 *
 *
 * @author Copyright (c) 2003 by BEA Systems. All Rights Reserved.
 */

public class Generate {

  public static void main(String args[]) throws Exception {

    //
    // Get an output factory
    //
    XMLOutputFactory xmlof = XMLOutputFactory.newInstance(); 
    System.out.println("FACTORY: " + xmlof);

    //
    // Instantiate a writer
    //
    XMLStreamWriter xmlw = xmlof.createXMLStreamWriter(new FileOutputStream ("outFile.xml")); 
    System.out.println("READER:  " + xmlw + "\n");

    //
    // Generate the XML
    //

    // Write the default XML declaration
    xmlw.writeStartDocument(); 
    xmlw.writeCharacters("\n"); 
    xmlw.writeCharacters("\n"); 

    // Write a comment
    xmlw.writeComment("this is a comment"); 
    xmlw.writeCharacters("\n"); 

    // Write the root element "person" with a single attribute "gender"
    xmlw.writeStartElement("person"); 
    xmlw.writeNamespace("one", "http://namespaceOne"); 
    xmlw.writeAttribute("gender","f"); 
    xmlw.writeCharacters("\n"); 

    // Write the "name" element with some content and two attributes
    xmlw.writeCharacters("    "); 
    xmlw.writeStartElement("one", "name", "http://namespaceOne"); 
    xmlw.writeAttribute("hair","pigtails"); 
    xmlw.writeAttribute("freckles","yes"); 
    xmlw.writeCharacters("Pippi Longstocking"); 

    // End the "name" element 
    xmlw.writeEndElement(); 
    xmlw.writeCharacters("\n"); 

    // End the "person" element
    xmlw.writeEndElement(); 

    // End the XML document
    xmlw.writeEndDocument(); 

    // Close the XMLStreamWriter to free up resources
    xmlw.close(); 

  }

}

XMLStreamWriterオブジェクトの取得

次のコードの抜粋で示すように、XMLOutputFactory.createXMLStreamWriter()メソッドを使用し、XMLドキュメントに基づいてXMLStreamWriterオブジェクトをインスタンス化します。

XMLStreamWriter xmlw = xmlof.createXMLStreamWriter(new FileOutputStream ("outFile.xml"));

この例では、xmlofXMLOutputFactoryインスタンスに当たります。

createXMLStreamWriter()メソッドの様々なシグネチャにより、以下のXMLドキュメント・フォーマットをパラメータとして扱うことができます。

  • java.io.OutputStream (例で示します)

  • java.io.Writer

  • javax.xml.transform.Result (JAXP API http://java.sun.com/xml/で指定されています)

出力ストリームへのXML宣言の追加

次のコードの抜粋で示すように、XMLStreamWriter.writeStartDocument()メソッドを使用し、XMLドキュメントの1行目としてXML宣言を追加します。

xmlw.writeStartDocument();

引数を指定しない場合、このメソッドは次のデフォルトXML宣言を記述します。

<?xml version='1.0' encoding='utf-8'?>

別のエンコーディングまたはXMLバージョンを指定する場合は、引数を次のように指定したwriteStartDocument()メソッドを使用します。

  • writeStartDocument(java.lang.String version)

  • writeStartDocument(java.lang.String encoding, java.lang.String version)

writeStartDocument()メソッドでエンコーディングを設定しても、基底の出力の実際のエンコーディングは設定されません。このエンコーディング設定用の引数は、XML宣言のencoding属性に対してどの値が書き込まれるかを指定するものです。出力のエンコーディングを実際に設定するには、対応するXMLOutputFactory.createXMLStreamWriter()メソッドでXMLStreamWriterのインスタンスを作成する際にencodingパラメータを指定する必要があります。

出力ストリームへの標準XMLイベントの追加

XMLStreamWriter.writeXXX() XXXメソッドを使用すると、開始要素、終了要素、コメント、CDATA、エンティティ参照などの標準的なXMLイベントを出力ストリームに追加できます。writeStartElement(), writeEndElement(), writeComment(), writeCData()などの特定のイベントを指します。テキスト・データまたは名前をStringとして渡すことにより、大部分の要素を作成できます。

XMLStreamWriterインタフェースでは、データの検証や、ドキュメントが整形式かどうかのチェックは行われません。各開始要素と終了要素が対応しているかどうかなどの確認は、プログラマの役目です。また、開始要素と終了要素のイベントが正しくネストされているかどうかを確認することも、プログラマに任されています。テキスト・ファイルへの書込み時に出力XMLを読みやすくするには、writeCharacters("\n")メソッドを使用して、適切な場所に新しい行を追加します。

たとえば、次のような小さなXMLを作成するとします。

<!-- This is a comment -->
<name>Jane Doe</name>

出力ストリームにこの要素を追加するJavaコードは次のようになります。

xmlw.writeComment("This is a comment");
xmlw.writeCharacters("\n");

xmlw.writeStartElement("name");
xmlw.writeCharacters("Jane Doe");
xmlw.writeEndElement();
xmlw.writeCharacters("\n");

属性とネームスペース宣言の開始要素への追加

開始要素イベントの直後にwriteAttribute()メソッドを使用して、属性を要素に追加できます。バインド対象のURIとともに属性の接頭辞を指定することも、属性をまったく指定しないことも可能です。

たとえば、次のような小さなXMLを作成するとします。

<person gender="f">

このXMLを作成するJavaコードは次のとおりです。

xmlw.writeStartElement("person");
xmlw.writeAttribute("gender","f");
xmlw.writeCharacters("\n");

writeNamespace()メソッドを使用すると、出力ストリームにネームスペースを記述できます。現在のイベントで開始要素などのネームスペースの記述を有効にするのはプログラマの役目です。現在のイベントでネームスペースの記述が無効になっている場合は、javax.xml.stream.XMLStreamExceptionが送出されます。イベントの接頭辞やそのバインド対象となるURIを指定するには、それに応じた形式のwriteXXX()メソッドを使用します。

たとえば、次のXML出力では、<person>要素のネームスペース宣言、および<one>子要素用に指定したone接頭辞を示します。

<person xmlns:one="http://namespaceOne" gender="f">
    <one:name hair="pigtails" freckles="yes">Pippi Longstocking</one:name>
</person>

このXMLを作成するJavaコードは次のとおりです。

    // Write the root element "person" with a single attribute "gender"
    xmlw.writeStartElement("person");
    xmlw.writeNamespace("one", "http://namespaceOne");
    xmlw.writeAttribute("gender","f");
    xmlw.writeCharacters("\n");

    // Write the "name" element with some content and two attributes
    xmlw.writeCharacters("    ");
    xmlw.writeStartElement("one", "name", "http://namespaceOne");
    xmlw.writeAttribute("hair","pigtails");
    xmlw.writeAttribute("freckles","yes");
    xmlw.writeCharacters("Pippi Longstocking");

    // End the "name" element
    xmlw.writeEndElement();
    xmlw.writeCharacters("\n");

    // End the "person" element
    xmlw.writeEndElement();

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

プログラミング慣行として、作業終了時にXMLStreamWriterを明示的にクローズしてリソースを解放します。ライターをクローズするには、XMLStreamWriter.close()メソッドを使用します。以下に例を示します。

    // Close the XMLStreamWriter to free up resources
    xmlw.close();

XMLInputFactoryインタフェース用に定義されたプロパティ

表4-2では、XMLInputFactoryを使用してXMLStreamReaderオブジェクトまたはXMLEventReaderオブジェクトを生成する際に設定可能な標準プロパティを示します。

表4-2のプロパティにはjavax.xml.stream.isValidatingのように、いずれも先頭にjavax.xml.streamが付きます。

表4-2 Standard XMLInputFactoryの標準プロパティ

プロパティ 説明 戻り値の型 デフォルト値
isValidating

実装固有のDTD検証を有効にするか無効にするかを指定します。

Boolean

False

isNamespaceAware

ネームスペース処理を有効にするか無効にするかを指定します。XML 1.0がサポートされている場合に使用。

Boolean

True

isCoalescing

隣接する文字データをまとめるかどうかを指定します。

Boolean

False

isReplacingEntityReferences

内部エンティティ参照を置換テキストに置き換え、文字として報告するかどうかを指定します。

Boolean

True

isSupportingExternalEntities

解析対象の外部エンティティを解決するかどうかを指定します。

Boolean

False

supportDTD

使用するプロセッサがDTDをサポートするかどうかを指定します。

Boolean

True

reporter

使用するjavax.xml.stream.XMLReporterの実装を指定します。

XMLReporter

Null

resolver

使用するjavax.xml.stream.XMLResolverの実装を指定します。

XMLResolver

Null

allocator

使用するjavax.xml.stream.util.XMLEventAllocatorの実装を指定します。

util.XMLEventAllocator

Null


XMLOutputFactoryインタフェース用に定義されたプロパティ

表4-3では、XMLOutputFactoryを使用してXMLStreamWriterオブジェクトまたはXMLEventWriterオブジェクトを生成する際に設定可能な標準プロパティを示します。

表4-3のプロパティにはjavax.xml.stream.isValidatingのように、いずれも先頭にjavax.xml.streamが付きます。

表4-3 XMLOutputFactoryの標準プロパティ

プロパティ 説明 戻り値の型 デフォルト値
isRepairingNamespaces

ライターがデフォルト・ネームスペース接頭辞宣言を使用するかどうかを指定します。

XMLの生成時にStAXプロセッサがネームスペースと接頭辞を修正する方法には、いくつかの厳密なルールがあります。詳細は、StAX仕様(http://www.jcp.org/en/jsr/detail?id=173)を参照してください。

Boolean

False