13 Java DOM API for XMLType

Java DOM API for XMLTypeでは、DOMを使用してXMLTypeインスタンスを操作できます。これを使用すると、Java Database Connectivity (JDBC)を介してXMLデータをフェッチするなど、JavaでXMLデータを操作できます。

13.1 Java DOM API for XMLTypeの概要

Oracle XML DBはJava Document Object Model (DOM) Application Program Interface (API) for XMLTypeをサポートします。これはXML Schemaに基づく文書とスキーマに基づかない文書の両方に対する、クライアントおよびサーバー用の汎用APIです。

DOMは、XML文書のメモリー内ツリーベースのオブジェクト表現で、要素および属性へのプログラム・アクセスを可能にします。DOMオブジェクトおよびインタフェースは、W3C勧告の一部です。PL/SQL API for XMLTypeで説明したとおり、Oracle XML DB DOM APIは、W3CのDOMレベル1.0およびレベル2.0のコア勧告に準拠しています。

Java DOM API for XMLTypeでは、Oracle XML DBに格納されたすべての整形式のXML文書を処理します。XML文書は、XML Schemaに基づくかどうか、および基礎となるXMLType記憶域モデルの形式に関係なく、同様に表示されます。Java DOM APIは、クライアントおよびサーバーの両方で動作します。

Java DOM API for XMLTypeを使用すると、別のキャラクタ・セットでエンコードされたデータからXMLTypeインスタンスを作成できます。

Java DOM API for XMLTypeを使用して、JavaアプリケーションからOracle XML DBリポジトリに格納されたXML文書にアクセスできます。ネーミングは、W3CのDOM勧告で指定されている、DOMへのJavaバインディングに準拠しています。リポジトリには、XML Schemaに基づくドキュメントおよび基づかないドキュメントの両方を含めることができます。

JDBCを使用してXMLTypeデータにアクセスするには、クラスoracle.xdb.XMLTypeを使用します。

Java DOM API for XMLTypeは、Javaパッケージoracle.xml.parser.v2を使用して実装されます。

13.2 JDBCを使用したXMLTypeデータへのアクセス

Java Database Connectivity (JDBC)は、Oracle XML DB内のXML文書など、Oracle Database内のすべてのデータにアクセスするための、Javaアプリケーション用のSQLベースの方法です。

Javaクラスoracle.xdb.XMLTypeまたはJavaインタフェースjava.sql.SQLXMLを使用して、XMLデータを作成します。

XMLデータのJDBC 4.0標準データ型はjava.sql.SQLXMLです。getObject()メソッドでは、oracle.xdb.XMLType型のオブジェクトが戻されます。Oracle Database 11gリリース2 (11.2.0.3)から、oracle.xdb.XMLTypeがインタフェースjava.sql.SQLXMLを実装しています。

13.2.1 JDBCを使用したOracle XML DB内のXML文書へのアクセス

JDBCユーザーは、XMLType表を問い合せて、SQL XMLTypeデータ型でサポートされるすべてのSQL/XML関数をサポートするJDBC XMLTypeインタフェースを取得できます。Java(JDBC)API for XMLTypeインタフェースは、DOMDocumentインタフェースを実装できます。

例13-1に、JDBCを使用してXMLType表を問い合せる方法を示します。

次のいずれかの方法で、JDBCを使用してXMLTypeデータを選択できます。

  • SQLでSQL/XML関数XMLSerializeを使用し、Javaでoracle.jdbc.OracleClobまたはjava.lang.Stringインスタンスとして結果を取得します。例13-2のJavaスニペットに、これを示します。

  • ResultSetでメソッドgetSQLXML()をコールして、SQLXMLインスタンス全体を取得します。このメソッドの戻り値は、java.sql.SQLXML型です。次に、インタフェースSQLXMLでJavaメソッドを使用し、データにアクセスできます。この方法を例13-3に示します。

例13-3では、getObject()メソッドを使用してResultSetからXMLTypeインスタンスを直接取得します。

例13-4では、XMLType型の出力パラメータをSQL文にバインドします。この出力パラメータは、XMLTypeデータ型として登録されます。

例13-1 JDBCを使用したXMLType表の問合せ

PreparedStatement statement = connection.prepareStatement("SELECT e.poDoc FROM po_xml_tab e"); 

ResultSet resultSet = statement.executeQuery();

while(resultSet.next())
{
  // Get result as SQLXML data.
  // Use that to get a DomSource instance.
  SQLXML sqlXml = resultSet.getSQLXML(1);
  DomSource source = sqlXml.getSource(DOMSource.class);

  // Get document from the DomSource instance as a DOM node.
  Document document = (Document) source.getNode();
  
  // Use the document object
  ...
}

例13-2 getString()およびgetCLOB()を使用したXMLTypeデータの選択

PreparedStatement statement = connection.prepareStatement(
  "SELECT XMLSerialize(DOCUMENT e.poDoc AS CLOB) poDoc, " +
  "XMLSerialize(DOCUMENT e.poDoc AS VARCHAR2(2000)) poString " +
  " FROM po_xml_tab e");
     
ResultSet resultSet = statement.executeQuery();
while(resultSet.next())
{
  // The first result is an OracleClob instance
  OracleClob clob = resultSet.getClob(1));
  
  // The second result is a String instance
  String poString = resultSet.getString(2);

  // Use clob and poString
  ... 
}

例13-3 getSQLXML()を使用してXMLTypeデータを戻す方法

PreparedStatement statement = connection.prepareStatement(
                           "SELECT e.poDoc FROM po_xml_tab e"); 

ResultSet resultSet = statement.executeQuery(); 

while(resultSet.next())
{ 
  // Get the SQLXML
  SQLXML sqlXml = resultSet.getSQLXML(1); 

  // Convert the SQLXML to an xmlString instance
  String xmlString = sqlXml.getString();

  //Use the xmlString instance
  ...
}

例13-4 出力パラメータを使用してXMLTypeデータを戻す方法

public void doCall (String[] args) throws Exception 
{ 
  //  CREATE OR REPLACE FUNCTION getPurchaseOrder(reference VARCHAR2) 
  //  RETURN XMLTYPE 
  //  AS 
  //    xml XMLTYPE; 
  //  BEGIN 
  //    SELECT OBJECT_VALUE INTO xml 
  //      FROM purchaseorder 
  //      WHERE XMLCast(XMLQuery('$p/PurchaseOrder/Reference'
  //                             PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
  //                    AS VARCHAR2(30))
  //            = reference;
  //      RETURN xml; 
  //  END;
  
  String SQLTEXT = "{? = call getPurchaseOrder('BLAKE-2002100912333601PDT')}"; 
  super.doSomething(args); 
  createConnection(); 
  try 
  { 
    System.out.println("SQL := " + SQLTEXT); 
    CallableStatement sqlStatement = getConnection().prepareCall(SQLTEXT); 
    sqlStatement.registerOutParameter (1, java.sql.Types.SQLXML); 
    sqlStatement.execute(); 

    SQLXML sqlXml = sqlStatement.getSQLXML(1); 
    System.out.println(sqlXml.getString()); 
  } 
  catch (SQLException exception) 
  { 
    if (sqlStatement != null) 
    { 
      sqlStatement.close(); 
      throw exception; 
    } 
  }
}

13.3 JDBCを使用したXMLデータベース文書の操作

Oracle XML DBでJava Database Connectivity (JDBC)を使用して、データベースに格納されたXMLTypeデータを更新、挿入および削除できます。

注意:

XMLTypeメソッドtransform()は、OCIドライバでのみ機能します。

Thin JDBCドライバでは、すべてのoracle.xdb.XMLType関数がサポートされているわけではありません。oracle.xdb.XMLTypeクラスとOCIドライバを使用しない場合、XMLのインテリジェント処理に関連したパフォーマンスのメリットを失う可能性があります。

XMLTypeデータを次のいずれかの方法で、更新、挿入または削除できます。

  • 文字列をINSERTUPDATEまたはDELETE文にバインドし、SQL内でXMLTypeコンストラクタを使用してXMLインスタンスを作成します。例13-5に、これを示します。

  • PreparedStatementインスタンスでsetSQLXML()を使用して、XMLTypeインスタンス全体を設定します。例13-6に、これを示します。

SQLXML値を選択すると、JDBCによって、列がSQLXMLとして記述されます。列型の名前を選択し、それをSQLXMLと比較すると、SQLXMLインスタンスを処理しているかどうかを確認できます。例13-7に、これを示します。

例13-8では、XMLType列に格納されているPurchaseOrder要素内のdiscount要素を更新します。ここでは、JDBCおよびSQLXMLを使用します。XMLパーサーを使用してDOMツリーを更新し、更新されたXML値をXMLType列に書き込みます。

例13-9は、例13-8から得られる更新済の発注書を示します。

例13-5 SQLコンストラクタXMLTypeおよびJava文字列を使用したXMLType列の更新

PreparedStatement statement =
    connection.prepareStatement("UPDATE po_xml_tab SET poDoc = XMLType(?)");

String poString = "<PO><PONO>200</PONO><PNAME>PO_2</PNAME></PO>";

// Bind the string
statement.setString(1,poString);
statement.execute();

例13-6 SQLXMLを使用したXMLType列の更新

PreparedStatement statement =
    connection.prepareStatement("UPDATE po_xml_tab SET poDoc = ?");

String xmlString = "<PO><PONO>200</PONO><PNAME>PO_2</PNAME></PO>";
SQLXML sqlXml = connection.createSQLXML();
sqlXml.setString(xmlString);

// Bind the SQLXML
statement.setSQLXML(1, sqlXml);
statement.execute();

例13-7 JDBCを使用したXMLType列に関するメタデータの取得

PreparedStatement statement =
    connection.prepareStatement("SELECT poDoc FROM po_xml_tab");
ResultSet resultSet = statement.executeQuery();

// Get the resultSet metadata
ResultSetMetaData mdata = (ResultSetMetaData)resultSet.getMetaData();

// The column type is SQLXML
if (mdata.getColumnType(1) == java.sql.Types.SQLXML)
{
  // It is a SQLXML instance
}

例13-8 JDBCを使用したXMLType列の更新

public class UpdateXMLType
{
  static String qryStr =
    "SELECT x.poDoc from po_xml_tab x " +
    "WHERE XMLCast(XMLQuery('/PO/PONO/text()'" +
    " PASSING x.poDoc RETURNING CONTENT)" +
    " AS NUMBER)" +
    " = 200";

  static String updateXML(String xmlTypeStr)
  {
    System.out.println("\n===============================");
    System.out.println(xmlTypeStr);
    System.out.println("===============================");
    String outXML = null;

    try
    {
      DOMParser parser = new DOMParser();
      parser.setValidationMode(false);
      parser.setPreserveWhitespace (true);
      parser.parse(new StringReader(xmlTypeStr));

      System.out.println("XML string is well-formed");
      XMLDocument document = parser.getDocument();
      NodeList nl = document.getElementsByTagName("DISCOUNT");

      for(int i=0;i<nl.getLength();i++)      {
        XMLElement discount = (XMLElement)nl.item(i);
        XMLNode textNode    = (XMLNode)discount.getFirstChild();
        textNode.setNodeValue("10");
      }

      StringWriter sw = new StringWriter();
      document.print(new PrintWriter(sw));
      outXML = sw.toString();

      //Print modified xml
      System.out.println("\n===============================");
      System.out.println("Updated PurchaseOrder:");
      System.out.println(outXML);
      System.out.println("===============================");
    }
    catch (Exception e)
    {
      e.printStackTrace(System.out);
    }
    return outXML;
  }

  public static void main(String args[]) throws Exception
  {
    try
    {
      PreparedStatement statement = connection.createStatement();
      ResultSet resultSet = statement.executeQuery(qryStr);

      while(orset.next())
      {
        //retrieve PurchaseOrder xml document from database
        SQLXML sqlXml = resultSet.getSQLXML(1);

        //store this PurchaseOrder in po_xml_hist table
        statement = connection.prepareStatement("INSERT INTO po_xml_hist VALUES(?)");
        statement.setSQLXML(1,sqlXml); // bind the SQLXML instance
        statement.execute();

        //update "DISCOUNT" element
        String newXML = updateXML(sqlXml.getString());
        // create a new instance of an XMLtype from the updated value
        SQLXML sqlXml2 = connection.createSQLXML();
        sqlXml2.setString(newXml);
        
        // update PurchaseOrder xml document in database
        statement = connection.prepareStatement(
                       "UPDATE po_xml_tab x SET x.poDoc =? WHERE " +
                       "XMLCast(XMLQuery('/PO/PONO/text()'" +
                       " PASSING value(xmltab) RETURNING CONTENT)" +
                       " AS NUMBER)" +
                       "= 200");

        statement.setSQLXML(1, sqlXml2); // bind the XMLType instance
        statement.execute();
        connection.commit();
        System.out.println("PurchaseOrder 200 Updated!");
      }

      //delete PurchaseOrder 1001
      statement.execute("DELETE FROM po_xml x WHERE" +
                        "XMLCast(XMLQuery('/PurchaseOrder/PONO/text()'" +
                        " PASSING value(xmltab) RETURNING CONTENT)" +
                        " AS NUMBER)" +
                        "= 1001");

      System.out.println("PurchaseOrder 1001 deleted!");
    }
    catch(Exception e)
    {
      e.printStackTrace(System.out);
    }
  }
}

例13-9 更新済の発注書

<?xml version = "1.0"?>
<PurchaseOrder>
  <PONO>200</PONO>
  <CUSTOMER>
   <CUSTNO>2</CUSTNO>
   <CUSTNAME>John Nike</CUSTNAME>
   <ADDRESS>
    <STREET>323 College Drive</STREET>
    <CITY>Edison</CITY>
    <STATE>NJ</STATE>
    <ZIP>08820</ZIP>
   </ADDRESS>
   <PHONELIST>
    <VARCHAR2>609-555-1212</VARCHAR2>
    <VARCHAR2>201-555-1212</VARCHAR2>
   </PHONELIST>
  </CUSTOMER>
  <ORDERDATE>20-APR-97</ORDERDATE>
  <SHIPDATE>20-MAY-97 12.00.00.000000 AM</SHIPDATE>
  <LINEITEMS>
   <LINEITEM_TYP LineItemNo="1">
    <ITEM StockNo="1004">
     <PRICE>6750</PRICE>
     <TAXRATE>2</TAXRATE>
    </ITEM>
    <QUANTITY>1</QUANTITY>
    <DISCOUNT>10</DISCOUNT>
   </LINEITEM_TYP>
   <LINEITEM_TYP LineItemNo="2">
    <ITEM StockNo="1011">
     <PRICE>4500.23</PRICE>
     <TAXRATE>2</TAXRATE>
    </ITEM>
    <QUANTITY>2</QUANTITY>
    <DISCOUNT>10</DISCOUNT>
   </LINEITEM_TYP>
  </LINEITEMS>
  <SHIPTOADDR>
   <STREET>55 Madison Ave</STREET>
   <CITY>Madison</CITY>
   <STATE>WI</STATE>
   <ZIP>53715</ZIP>
  </SHIPTOADDR>
</PurchaseOrder>

13.4 JDBCを使用した、データベースへの大規模なXML文書のロード

Java Database Connectivity (JDBC)を使用して大規模なXML文書をデータベースにロードするには、Java CLOBオブジェクトを使用して文書を保持し、JavaメソッドinsertXML()を使用して挿入します。

大規模なXML文書(通常4000文字を超える場合)がJDBCのStringオブジェクトを使用してXMLTypeの表または列に挿入されると、次のランタイム・エラーが発生します。

"java.sql.SQLException: Data size bigger than max size for this type"

このエラーは、JavaのOracleClobオブジェクトを使用して大規模なXML文書を保持することで回避できます。例13-10に、このテクニックを使用するコードを示します。これはXMLTypeメソッドのinsertXML()を定義します。これを使用して、大規模なXML文書が表poTableXMLTypeの列purchaseOrderに挿入されます。XMLType表の場合も同じ方法を使用できます。

メソッドinsertXML()では、XML文書を含むOracleClobオブジェクトを使用します。インタフェースOracleClobは、標準JDBCインタフェースjava.sql.Clobのサブインタフェースです。メソッドinsertXML()OracleClobオブジェクトをJDBCのプリコンパイルされた文にバインドします。これによりデータがXMLType列に挿入されます。

insertXML()を使用するための前提条件は、次のとおりです。

  • Oracle Databaseがリリース9.2.0.1以上であること。

  • ターゲット・データベース表が存在すること。例を実行する前に、次のSQLを実行してください。

    CREATE TABLE poTable (purchaseOrder XMLType);

XMLTypeメソッドのinsertXML()の仮パラメータは、次のとおりです。

  • xmlString - XMLType列に挿入するXMLデータ

  • connection - データベース接続オブジェクト(Oracle Connection Object)

JavaメソッドinsertXML()は、メソッドgetCLOB()をコールして、XMLデータを格納するCLOBオブジェクトを作成して戻します。getCLOB()メソッドの仮パラメータは例13-11で定義され、次のとおりです。

  • xmlString - XMLType列に挿入するXMLデータ

  • connection - データベース接続オブジェクト(Oracle Connection Object)

例13-10 JDBCを使用したXMLType列の挿入

private void insertXML(Connection connection, String xmlString)
{
  OracleClob clob = null;
  try
  {
    String query = "INSERT INTO potable (purchaseOrder) VALUES (XMLType(?)) ";

    // Get the statement Object
    PreparedStatement statement = connection.prepareStatement(query);

    // Get the OracleClob instance from xmlString
    clob = getOracleClob(connection, xmlString);
    statement.setObject(1, clob);

    // Execute the prepared statement
    if (statement.executeUpdate () == 1)
    {
      System.out.println ("Successfully inserted a Purchase Order");
    }
  }
  catch(Exception exp)
  {
    exp.printStackTrace();
  }
  finally 
  {
    if(clob !=null)
      clob.close();
  }
}

例13-11 OracleClobインスタンスへのXML文字列の変換

private OracleClob getOracleClob(Connection connection, String xmlString) throws SQLException
{
    OracleClob clob =(OracleClob) connection.createClob();
    clob.setString(1, xmlString);
    return clob;
}

13.5 Thick接続を使用したJava DOM APIに対するMS Windows Javaセキュリティ・マネージャの権限

アプリケーションのセキュリティ・ポリシーを実装するためにMS Windows上でJavaセキュリティ・マネージャ(クラスSecurityManager)を使用する場合は、Thick接続でJava DOM API for XMLTypeを使用するために、特定の権限をセキュリティ・ポリシー・ファイルに追加する必要があります。

例13-12では、このようなポリシー・ファイルの内容を示しています。ここで、c:\myworkspaceはOracle XML DBに関連するjarを含むワークスペース・フォルダです。(ポリシー・ファイルは、同じフォルダにある必要があります。)

例13-12で使用しているライブラリは、orageneric12およびoraxml12です。最後の2文字(ここでは12)は、データベースのメジャー・リリース番号に対応している必要があります(したがって、たとえばOracle Database 13 リリース2の場合、orageneric13oraxml13を使用します)。

ポリシー・ファイルを作成すると、次のコマンドライン・スイッチを使用してプログラムを呼び出すことができます。

-Djava.security.manager=default -Djava.security.policy=c:\myworkspace\ojdbc.policy

例13-12 Java DOM APIの権限を付与するポリシー・ファイル

grant codeBase "file:c:\myworkspace" {
  permission java.lang.RuntimePermission "loadLibrary.orageneric12";
  permission java.lang.RuntimePermission "loadLibrary.oraxml12";
}
 
grant codeBase "file:c:\myworkspace\xdb6.jar" {
  permission java.lang.RuntimePermission "loadLibrary.orageneric12";
  permission java.lang.RuntimePermission "loadLibrary.oraxml12";
}
 
grant codeBase "file:c:\myworkspace\ojdbc6.jar" {
  permission java.lang.RuntimePermission "loadLibrary.orageneric12";
  permission java.lang.RuntimePermission "loadLibrary.oraxml12";
}

13.6 XML Schemaに基づく文書の作成

XML Schemaに基づく文書を作成するには、Java DOM API for XMLTypeの拡張機能を使用して、使用するXML Schema URLを指定します。また、作成中のDOMが指定されたXML Schemaに準拠するかどうか(適切な子が適切な文書に挿入されているか)も検証します。

注意:

Java DOM API for XMLTypeは型および制約のチェックは実行しません

DOMオブジェクトの作成後は、Oracle XML DB Resource API for Javaを使用して、DOMオブジェクトをOracle XML DBリポジトリに保存できます。XML文書は次の適切な形式で格納されます。

  • BLOBインスタンス(スキーマに基づかない文書の場合)

  • XML Schemaで指定された形式(XML Schemaに基づく文書の場合)

例13-13では、Java DOM API for XMLTypeを使用してDOMオブジェクトを作成し、関連するXML Schemaで指定された形式で格納します。この例では、XML Schemaに対する検証は示されていません。

例13-13 Java DOM APIを使用したDOMオブジェクトの作成

PreparedStatement statement = connection.prepareStatement(
                                "update po_xml_XMLTypetab set poDoc = ? ");                              
String xmlString = "<PO><PONO>200</PONO><PNAME>PO_2</PNAME></PO>";

OracleClob clob = (OracleClob)connection.createClob();
clob.setString(1, xmlString);
SQLXML sqlXml    = clob.toSQLXML();

DOMSource domSource = sqlXml.getSource(DOMSource.class);
Document  document  = (Document) domSource.getNode();
Element   rootElem  = document.createElement("PO");
document.insertBefore(document, rootElem, null);

SQLXML sqlXml2 = clob.toSQLXML();

DOMResult domResult = sqlXml2.setResult(DomResult.class);
domResult.setNode(document);
statement.setSQLXML(1, sqlXml2);
statement.execute();

13.7 Java (JDBCまたはSQLJ)でのXMLTypeインスタンス表現

XMLTypeインスタンスは、oracle.xdb.XMLTypeによってJavaで表現されます。XMLTypeインスタンスがJDBCまたはSQLJのクライアントを使用してフェッチされると、このインスタンスは提供されたXMLTypeクラスのオブジェクトとして自動的に明示されます。

このクラスのオブジェクトは、データ操作言語(DML)文の値としてバウンドできます。通常、この値はXMLTypeです。

13.8 Java DOM API for XMLTypeのクラス

Oracle XML DBは、W3CのDOMレベル2勧告をサポートします。また、アプリケーションとOracle XML Developer's Kit for Javaの相互作用を容易にするOracle固有の拡張機能も提供します。Java DOM API for XMLTypeでは、W3C DOMインタフェースを実装するクラスが提供されます。

XMLDocumentは、インスタンス化されたXML文書用にDOMを表すクラスです。次のようにして、文書および接続オブジェクトからSQLXMLインスタンスを取得できます。

SQLXML sqlXml = connection.createSQLXML();
DOMResult domResult = sqlXml.setResult(DOMResult.class);
domResult.setNode(document);

表13-1に、Java DOM API for XMLTypeのクラスおよび実装されるW3CのDOMインタフェースを示します。Java DOM APIクラスは、oracle.xml.parser.v2パッケージに入っています。

表13-1 Java DOM API for XMLType: クラス

Java DOM API for XMLTypeのクラス W3CのDOMインタフェース勧告のクラス
XMLDocument
org.w3c.dom.Document 
XMLCDATA
org.w3c.dom.CDataSection 
XMLComment
org.w3c.dom.Comment 
XMLPI
org.w3c.dom.ProcessingInstruction 
XMLText 
org.w3c.dom.Text 
XMLEntity
org.w3c.dom.Entity 
DTD
org.w3c.dom.DocumentType 
XMLNotation
org.w3c.dom.Notation 
XMLAttr
org.w3c.dom.Attribute 
XMLDomImplementation
org.w3c.dom.DOMImplementation 
XMLElement
org.w3c.dom.Element 
XMLAttrList
org.w3c.dom.NamedNodeMap 
XMLNode 
org.w3c.dom.Node 

関連項目:

OTNのOracle XML DB: アプリケーションとOracle XML Developer's Kit for Javaの相互作用のためのOracle拡張機能

13.9 Java DOM API for XMLTypeの使用

XMLType表または列からデータを取得し、そこからJava XMLDocumentインスタンスを取得します。Java DOM API for XMLTypeを使用して、データのDOMツリーの要素を操作します。

Java DOM API for XMLTypeを使用すると、任意のレベルにある文書内のノードを検索および取得できます。これにより、その場で(動的に)作成するなど、XML文書をプログラムで作成できます。これらの文書は、登録されたXML Schemaに準拠することもあれば、しないこともあります。Java API for XMLTypeはDOM 2.0勧告に準拠し、名前空間を認識します。

図13-1に、Java DOM API for XMLTypeの使用方法を示します脚注1。次のステップを実行します。

  1. XMLType表または表のXMLType列からXMLデータを取り出します。XMLデータをフェッチすると、OracleによってDocumentインスタンスが作成されます。これにより、getNode()メソッドを使用してXMLDocumentインスタンスを取得できます。

  2. Java DOM API for XMLTypeを使用してDOMツリーの要素を操作します。変更されたデータはXMLTypeインスタンスに格納されますが、データはJDBC更新を使用して戻されます。

XMLTypeおよびXMLDocumentインスタンスは、各クラスでfree()メソッドを使用してクローズする必要があります。クローズすると、保持されていた基礎となるメモリーがすべて解放されます。

図13-1 Java DOM API for XMLTypeの使用

図13-1の説明が続きます
「図13-1 Java DOM API for XMLTypeの使用」の説明

13.10 Javaを使用した大規模XMLノードの処理

Oracle XML DBでは、抽象ストリームおよびストリーム操作の各メソッドが提供され、これらを使用して、64 KBを超えるXMLノードを処理できます。Thickまたはkprb接続でJavaクラスXMLNodeおよびXMLAttrを使用して、大規模ノードを操作します。

注意:

大規模ノード機能は、Thickまたはkprb接続でのみ動作します。Thin接続では動作しません。

Oracle Database 11gリリース(11.1)以前は、Oracle XML DBにより処理されるテキスト・ノードまたは属性値のサイズはそれぞれ64KBに制限されていました。リリース11.1以降、この制限はなくなりました。

以前ノードのサイズが制限されていたのは、ノード値を設定および取得するJavaメソッドでjava.lang.String型の引数のみがサポートされていたためです。文字列の最大サイズはJava VMの実装により依存していますが、限定されています。リリース11.1以前は、oracle.xdb.dom.XDBNode.javaクラス内に含まれているノード値を管理するJava DOM APIは次のようになっていました。

public String getNodeValue ();
public void setNodeValue (String value);

リリース11.1以前は、oracle.xdb.dom.XDBAttribute.javaクラス内に含まれている属性を管理するJava DOM APIは次のようになっていました。

public String getValue ();
public void setValue (String value);

Oracle Database 11gリリース1 (11.1)から、パッケージoracle.xdb.domは非推奨になっています。このパッケージ内のJavaクラスXDBNodeおよびXDBAttributeは、パッケージoracle.xml.parser.v2内でそれぞれクラスXMLNodeおよびXMLAttrに置き換えられています。また、これらのDOM APIはリリース11.1では拡張され、任意のサイズのテキスト・ノード値およびバイナリ・ノード値をサポートしています。

13.10.1 Java DOMへのストリーム拡張

Java StringReader、およびWriterデータはすべてUCS2で表現されます。これは、データベース・キャラクタ・セットと同じではない場合があります。また、ノード文字データはキャラクタ・セットIDでタグ付けされており、ノード値が移入するときに設定されます。

次に示すoracle.xml.parser.v2.XMLNode.javaのメソッドにより、サイズが64KBを超えるノードにアクセスできます。リーフ・ノード(属性、PICDATAなど)ではないノードを取得または設定しようとすると、これらのAPIにより例外が発生します。また、その値を実際に書き込み、ノードへのストリーム・アクセス状態を維持する場合に使用するリソースを解放するclose()を使用してください。

13.10.1.1 Get-Pullモデル

メソッドgetNodeValueAsBinaryStream()およびgetNodeValueAsCharacterStream()を使用して、取出しモードのパーサーによってDOMノードの値を取得できます。Oracle XML DBでは、パーサーによって書き込まれた入力ストリームからイベント・データを読み取ります。

バイナリ入力ストリームの場合:

public java.io.InputStream getNodeValueAsBinaryStream () 
  throws java.io.IOException,
         DOMException;

メソッドgetNodeValueAsBinaryStream()は、このクラスの定義メソッドを使用して読み取ることができる java.io.InputStreamのインスタンスを戻します。ノードのデータ型はRAWまたはBLOBである必要があります。それ以外の場合は、IOExceptionが発生します。次の例では、バイナリ50バイトのセグメントのノード値を読み取っています。

...
oracle.xml.parser.v2.XMLNode node = null;
...
java.io.InputStream value = node.getNodeValueAsBinaryStream ();
// now read InputStream...
byte buffer [] = new byte [50];
int returnValue = 0;
while ((returnValue = value.read (buffer)) != -1)
{
  // process next 50 bytes of node
}
...

文字入力ストリームの場合:

public java.io.Reader getNodeValueAsCharacterStream() 
  throws java.io.IOException,
         DOMException;

メソッドgetNodeValueAsCharacterStream()は、このクラスの定義メソッドを使用して読み取ることができるjava.io.Readerのインスタンスを戻します。ノードのデータ型が文字でもCLOBでもない場合、まずノード・データは文字に変換されます。すべてのノード・データは最終的には文字形式になり、必要に応じてUCS2に変換されます。次の例では、50文字のセグメントのノード値を読み取っています。

...
oracle.xml.parser.v2.XMLNode node = null;
...
java.io.Reader value = node.getNodeValueAsCharacterStream ();
// now read InputStream
char buffer [] = new char [50];
int returnValue = 0;
while ((returnValue = value.read (buffer)) != -1)
{
  // process next 50 characters of node
}
...
13.10.1.2 Get-Pushモデル

このモデルでは、プッシュ・モードのパーサーを使用して、DOMノードの値を取得します。Oracle XML DBでは、パーサーによって読み取られた出力ストリームにノード・データを書き込みます。

バイナリ出力ストリームの場合:

public void getNodeValueAsBinaryStream (java.io.OutputStream pushValue) 
  throws java.io.IOException,
         DOMException;

pushValueで指定されるjava.io.OutputStreamの状態はopenである必要があります。ノードのデータ型はRAWまたはBLOBである必要があります。それ以外の場合は、IOExceptionが発生します。ノード・バイナリ・データはOutputStreamwrite()メソッドを使用してpushValueに書き込まれ、ノード値が完全にストリームに書き込まれるとclose()メソッドがコールされます。

文字出力ストリームの場合:

public void getNodeValueAsCharacterStream (java.io.Writer pushValue) 
  throws java.io.IOException,
         DOMException;

pushValueで指定されるjava.io.Writerの状態はopenである必要があります。ノードのデータ型が文字でもCLOBでもない場合、まずデータは文字に変換されます。常に文字形式のノード・データは必要に応じてUCS2に変換され、java.io.Writerにプッシュされます。

13.10.1.3 Set-Pullモデル

このモデルでは、取出しモードのパーサーを使用して、DOMノードの値を設定します。Oracle XML DBでは、パーサーによって書き込まれた入力ストリームからイベント・データを読み取ります。

バイナリ入力ストリームの場合:

public void setNodeValueAsBinaryStream (java.io.InputStream pullValue) 
  throws java.io.IOException,
         DOMException;

pullValueで指定されるjava.io.InputStreamの状態はopenである必要があります。ノードのデータ型はRAWまたはBLOBである必要があります。それ以外の場合は、IOExceptionが発生します。pullValueのバイナリ・データ全体がInputStreamread()メソッドを使用して読み取られ、ノード値を置換します。

import java.io.InputStream;
import oracle.xml.parser.*;
...
oracle.xml.parser.v2.XMLNode node = null;
...
byte [] buffer = new byte [500];
java.io.InputStream  istream; //user-defined input stream
node.setNodeValueAsBinaryStream (istream);

文字入力ストリームの場合:

public void setNodeValueAsCharacterStream (java.io.Reader pullValue) 
  throws java.io.IOException,
         DOMException;

pullValueで指定されるjava.io.Readerの状態はopenである必要があります。ノードのデータ型が文字でもCLOBでもない場合、文字データはUCS2からノード・データ型に変換されます。ノードのデータ型が文字またはCLOBの場合、pullValueから読み取られた文字データは、UCS2からノードのキャラクタ・セットに変換されます。

13.10.1.4 Set-Pushモデル

このモデルでは、プッシュ・モードのパーサーを使用して、DOMノードの値を設定します。Oracle XML DBでは、パーサーによって読み取られた出力ストリームにノード・データを書き込みます。

バイナリ出力ストリームの場合:

public java.io.OutputStream setNodeValueAsBinaryStream () 
  throws java.io.IOException,
         DOMException;

メソッドsetNodeValueAsBinaryStream()は、コール元によるノード値の書込み先となるjava.io.OutputStreamのインスタンスを戻します。ノードのデータ型はRAWまたはBLOBである必要があります。それ以外の場合は、IOExceptionが発生します。次の例では、Oracle XML DBまたはOracle XML Developer's Kitが提供するjava.io.OutputStreamの実装に書き込むことで、ノード値をバイナリ・データに設定しています。

文字出力ストリームの場合:

public java.io.Writer setNodeValueAsCharacterStream () 
  throws java.io.IOException,
         DOMException;

メソッドsetNodeValueAsCharacterStream()は、コール元によるノード値の書込み先となるjava.io.Writerのインスタンスを戻します。書き込まれた文字データはまず、必要に応じてUCS2からノードのキャラクタ・セットに変換されます。ノードのデータ型が文字でもCLOBでもない場合、文字データはノード・データ型に変換されます。同様に、次の例では、Oracle XML DBまたはOracle XML Developer's Kitが提供するjava.io.Writerの実装に書き込むことで、ノード値を文字データに設定しています。

import java.io.Writer;
import oracle.xml.parser.*;
...
oracle.xml.parser.v2.XMLNode node = null;
...
char [] buffer = new char [500];
java.io.Writer  writer = node.setNodeValueAsCharacterStream ();
for (int k = 0; k < 10; k++)
{
  byte segment [] = new byte [50];
  // copy next subset of buffer into segment
  writer.write (segment);
}
writer.flush ();
writer.close();

Oracle XML DBはwriterまたはOutputStreamを作成し、それをノード値が完全に書き込まれるまで繰り返しwrite()メソッドをコールするユーザーに渡します。新規ノード値は、ユーザーがclose()メソッドをコールするときのみ反映されます。

関連項目:

13.11 バイナリXMLでのJava DOM APIおよびJDBCの使用

Java DOM API for XMLおよびJava Database Connectivity (JDBC)を使用して、Oracle XML DBに対して、バイナリXMLとしてエンコードされたXMLデータを読書きできます。この処理には通常の読書きプロシージャが関与します。

XMLデータは、データ型XMLTypeを使用してOracle XML DBに格納でき、この抽象データ型の記憶域モデルの1つが、XMLデータの簡潔なXML Schema対応のエンコーディングであるバイナリXMLです。バイナリXMLはデータベース内のXMLTypeの記憶域モデルとして使用することができますが、データベース外にあるXMLデータに対しても使用することができます。XMLデータのクライアント側処理には、Oracle XML DB内に格納されているデータや、データベース外に存在する一時データが関わることがあります。

バイナリXMLはXML Schemaに対応しており、必要性とデータに応じて、各種のコード体系を使用することができます。このため、バイナリXMLデータを操作するためには、関連するXML Schemaとエンコーディングについて、データとこのメタデータの両方が必要です。

データベースに格納されているXMLTypeデータの場合、このメタデータもデータベースに格納されます。ただし、データベースとデータのセットアップに応じて、メタデータが適用されるデータと同一のサーバーにメタデータが格納されない場合があります。この場合、データベースに対してバイナリXMLデータを読書きするためには、次のステップを実行する必要があります。

  1. メタデータのコンテキスト・インスタンスを作成します。

  2. このコンテキストを、データベース内のバイナリXMLデータにアクセスするために使用するデータ接続に関連付けます。データ接続は、専用接続でも接続プールでもかまいません。クラスjava.sql.ConnectionのメソッドgetDedicatedConn()およびgetConnPool()を使用して、それらの接続の型に応じて、これら2つの接続型へのハンドルを取得します。

すると、アプリケーションがデータ接続上でバイナリXMLデータをエンコードまたはデコードする必要がある場合、それに必要なメタデータが自動的にフェッチされます。一連の動作の全体は次のとおりです。

  1. クラスjava.sql.ConnectionにXMLデータ接続オブジェクトを作成します。

  2. パッケージoracle.xml.binxml内のメソッドBinXMLMetadataProviderFactory.createDBMetadataProvider()を使用して、必要に応じて1つ以上のメタデータ・コンテキストを作成します。メタデータ・コンテキストは、メタデータ・リポジトリと呼ばれることもあります。メタデータ・コンテキストは、専用接続または接続プールから作成することができます。

  3. メタデータ・コンテキストをバイナリXMLデータ接続に関連付けます。これには、パッケージoracle.xml.binxml内のメソッドDBBinXMLMetadataProvider.associateDataConnection()を使用します。

  4. (オプション) XMLデータがデータベース外に由来するものの場合は、メソッドoracle.xdb.XMLType.setFormatPref()を使用して、データベースに送信されるXMLデータがバイナリXML形式でエンコードされるように指定します。これは、DOM文書(クラスoracle.xdb.XMLType)に適用されます。バイナリXMLを指定しない場合、データはテキストとしてデータベースに送信されます。

  5. 通常のJavaメソッドを使用して、データベースに対してXMLデータを読書きします。バイナリXML文書のエンコードやデコードに必要なときは常に、メタデータ・コンテキストを使用して、必要なメタデータが自動的にフェッチされます。

    Java DOM API for XMLを使用して、クライアント・レベルのXMLデータに対して操作します。

例13-14に、これを示します。

例13-14 バイナリXML列でのJava DOM APIの使用

class PrintBinaryXML
{
  public static void printBinXML() throws SQLException, BinXMLException
  {
    // Create datasource to connect to local database
    OracleDataSource ods = new OracleDataSource();
    ods.setURL("jdbc:oracle:kprb");
    
    System.out.println("Starting Binary XML Java Example");

    // Create data connection
    Connection connection = ods.getConnection();
    // Create binary XML metadata context, using connection pool
    DBBinXMLMetadataProvider repos =
      BinXMLMetadataProviderFactory.createDBMetadataProvider();
    repos.setConnectionPool(ods);

    // Associate metadata context with data connection
    repos.associateDataConnection(connection);

    // Query XML data stored in SQLXML column as binary XML
    Statement statement = connection.createStatement();
    ResultSet resultSet = statement.executeQuery("SELECT doc FROM po_binxmltab");

    // Get the SQLXML object
    while (resultSet.next())
    {
      SQLXML sqlXml = resultSet.getSQLXML(1);

      // Convert SQLXML to a String
      String xmlString = sqlXml.getString();
      System.out.println(xmlString);
    }

    resultSet.close();
    statement.close();
    connection.close();

    System.out.println("Completed Binary XML Java Example");
  }
}

関連トピック



脚注の説明

脚注1:

ここでは、XMLデータがXML Schemaに登録済であり、XMLTypeの列に格納されていると想定しています。