Java DOM API for XMLTypeでは、DOMを使用してXMLTypeインスタンスを操作できます。これを使用すると、Java Database Connectivity (JDBC)を介してXMLデータをフェッチするなど、JavaでXMLデータを操作できます。
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を使用して実装されます。
関連項目:
『Oracle Database XML Java API Reference』
Java Database Connectivity (JDBC)は、Oracle XML DB内のXML文書など、Oracle Database内のすべてのデータにアクセスするための、Javaアプリケーション用のSQLベースの方法です。
XMLデータを作成するには、oracle.xdb.XMLType JavaクラスのcreateXML()メソッドを使用します。
注意:
入力としてストリームを引き渡す場合は、メソッドXMLType.createXML()とThickドライバを使用してください。この場合、Thinドライバは使用できません。
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を実装しています。
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.sql.CLOB、java.lang.Stringまたはoracle.sql.BLOBとして結果を取得します。例13-2のJavaスニペットに、これを示します。
PreparedStatementでメソッドgetObject()をコールして、XMLTypeインスタンス全体を取得します。このメソッドの戻り値は、oracle.xdb.XMLType型です。これによって、XMLTypeクラスでJava関数を使用して、データにアクセスできます。この方法を例13-3に示します。
例13-3では、getObject()メソッドを使用してResultSetからXMLTypeインスタンスを直接取得します。
例13-4では、XMLType型の出力パラメータをSQL文にバインドします。この出力パラメータは、XMLTypeデータ型として登録されます。
例13-1 JDBCを使用したXMLType表の問合せ
import oracle.xdb.XMLType;
...
OraclePreparedStatement stmt = (OraclePreparedStatement)
conn.prepareStatement("SELECT e.poDoc FROM po_xml_tab e");
ResultSet rset = stmt.executeQuery();
OracleResultSet orset = (OracleResultSet) rset;
while(orset.next())
{
// get the XMLType
XMLType poxml = (XMLType)orset.getObject(1);
// get the XMLDocument as a string...
Document podoc = (Document)poxml.getDOM();
}
例13-2 getStringVal()およびgetCLOB()を使用したXMLTypeデータの選択
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci8:@", "QUINE", "CURRY");
OraclePreparedStatement stmt =
(OraclePreparedStatement) conn.prepareStatement(
"SELECT XMLSerialize(DOCUMENT e.poDoc AS CLOB) poDoc, " +
"XMLSerialize(DOCUMENT e.poDoc AS VARCHAR2(2000)) poString " +
" FROM po_xml_tab e");
ResultSet rset = stmt.executeQuery();
OracleResultSet orset = (OracleResultSet) rset;
while(orset.next())
{
// the first argument is a CLOB
oracle.sql.CLOB clb = orset.getCLOB(1);
// the second argument is a string..
String poString = orset.getString(2);
// now use the CLOB inside the program
}
例13-3 getObject()を使用してXMLTypeデータを戻す方法
import oracle.xdb.XMLType;
...
PreparedStatement stmt = conn.prepareStatement(
"SELECT e.poDoc FROM po_xml_tab e");
ResultSet rset = stmt.executeQuery();
while(rset.next())
{
// get the XMLType
XMLType poxml = (XMLType)rset.getObject(1);
// get the XML as a string...
String poString = poxml.getStringVal();
}
例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')}";
CallableStatement sqlStatement = null;
XMLType xml = null;
super.doSomething(args);
createConnection();
try
{
System.out.println("SQL := " + SQLTEXT);
sqlStatement = getConnection().prepareCall(SQLTEXT);
sqlStatement.registerOutParameter (1, OracleTypes.OPAQUE,"SYS.XMLTYPE");
sqlStatement.execute();
xml = (XMLType) sqlStatement.getObject(1);
System.out.println(xml.getStringVal());
}
catch (SQLException SQLe)
{
if (sqlStatement != null)
{
sqlStatement.close();
throw SQLe;
}
}
}
Oracle XML DBでJava Database Connectivity (JDBC)を使用して、データベースに格納されたXMLTypeデータを更新、挿入および削除できます。
注意:
XMLTypeメソッドのextract()、transform()およびexistsNode()は、OCIドライバでのみ機能します。
Thin JDBCドライバでは、すべてのoracle.xdb.XMLType関数がサポートされているわけではありません。oracle.xdb.XMLTypeクラスとOCIドライバを使用しない場合、XMLのインテリジェント処理に関連したパフォーマンスのメリットを失う可能性があります。
XMLTypeデータを次のいずれかの方法で、更新、挿入または削除できます。
CLOBまたは文字列をINSERT、UPDATEまたはDELETE文にバインドし、SQL内でXMLTypeコンストラクタを使用してXMLインスタンスを作成します。例13-5に、これを示します。
PreparedStatementでsetObject()を使用して、XMLTypeインスタンス全体を設定します。例13-6に、これを示します。
XMLType値を選択すると、JDBCによって、列が不透明型として記述されます。列型の名前を選択し、それをXMLTYPEと比較すると、XMLTypeインスタンスを処理しているかどうかを確認できます。例13-7に、これを示します。
例13-8では、XMLType列に格納されているPurchaseOrder要素内のdiscount要素を更新します。ここではJDBCおよびoracle.xdb.XMLTypeクラスを使用します。XMLパーサーを使用してDOMツリーを更新し、更新されたXML値をXMLType列に書き込みます。
例13-9は、例13-8から得られる更新済の発注書を示します。
例13-10では、次のものがすべて処理されます。
XMLType表からのXMLTypeインスタンスの選択
XPath式に基づくXMLTypeインスタンスの一部の抽出
要素の有無の確認
XSLに基づく別のXML形式へのXMLTypeインスタンスの変換
XML Schemaに対するXMLType文書の妥当性の確認
例13-5 SQL UPDATEとコンストラクタXMLTypeを使用したXMLTypeデータの更新
OraclePreparedStatement stmt =
(OraclePreparedStatement) conn.prepareStatement(
"UPDATE po_xml_tab SET poDoc = XMLType(?)");
// the second argument is a string..
String poString = "<PO><PONO>200</PONO><PNAME>PO_2</PNAME></PO>";
// now bind the string..
stmt.setString(1,poString);
stmt.execute();
例13-6 SQL UPDATEとsetObject()を使用したXMLTypeデータの更新
import oracle.xdb.XMLType;
...
OraclePreparedStatement stmt =
(OraclePreparedStatement) conn.prepareStatement(
"UPDATE po_xml_tab SET poDoc = ?");
// the second argument is a string
String poString = "<PO><PONO>200</PONO><PNAME>PO_2</PNAME></PO>";
XMLType poXML = XMLType.createXML(conn, poString);
// now bind the string..
stmt.setObject(1,poXML);
stmt.execute();
例13-7 JDBCを使用したXMLTypeデータに関するメタデータの取得
import oracle.sql.*;
import oracle.jdbc.*;
...
OraclePreparedStatement stmt =
(OraclePreparedStatement) conn.prepareStatement(
"SELECT poDoc FROM po_xml_tab");
OracleResultSet rset = (OracleResultSet)stmt.executeQuery();
// Get the resultset metadata
OracleResultSetMetaData mdata =
(OracleResultSetMetaData)rset.getMetaData();
// Describe the column = the column type comes out as OPAQUE
// and column type name comes out as XMLTYPE
if (mdata.getColumnType(1) == OracleTypes.OPAQUE &&
mdata.getColumnTypeName(1).compareTo("SYS.XMLTYPE") == 0)
{
// It is an XMLtype instance
}
例13-8 JDBCを使用したXMLType列の要素の更新
-- Create po_xml_hist table to store old PurchaseOrders
CREATE TABLE po_xml_hist (xpo XMLType);
/* NOTE: You must have xmlparserv2.jar and xdb.jar in CLASSPATH */
import java.sql.*;
import java.io.*;
import oracle.xml.parser.v2.*;
import org.xml.sax.*;
import org.w3c.dom.*;
import oracle.jdbc.driver.*;
import oracle.sql.*;
import oracle.xdb.XMLType;
public class tkxmtpje
{
static String conStr = "jdbc:oracle:oci8:@";
static String user = "QUINE";
static String pass = "CURRY";
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)
Java DOM API for XMLType
Beta Draft Java DOM API for XMLType 15-7
{
System.out.println("\n===============================");
System.out.println("xmlType.getStringVal():");
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("xmlType.getStringVal(): xml String is well-formed");
XMLDocument doc = parser.getDocument();
NodeList nl = doc.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();
doc.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
{
System.out.println("qryStr=" + qryStr);
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci8:@", user, pass);
Statement s = conn.createStatement();
OraclePreparedStatement stmt;
ResultSet rset = s.executeQuery(qryStr);
OracleResultSet orset = (OracleResultSet) rset;
while(orset.next())
{
//retrieve PurchaseOrder xml document from database
XMLType xt = (XMLType)orset.getObject(1);
//store this PurchaseOrder in po_xml_hist table
stmt = (OraclePreparedStatement)conn.prepareStatement(
"INSERT INTO po_xml_hist VALUES(?)");
stmt.setObject(1,xt); // bind the XMLType instance
stmt.execute();
//update "DISCOUNT" element
String newXML = updateXML(xt.getStringVal());
// create a new instance of an XMLtype from the updated value
xt = XMLType.createXML(conn, newXML);
// update PurchaseOrder xml document in database
stmt = (OraclePreparedStatement)conn.prepareStatement(
"UPDATE po_xml_tab x SET x.poDoc =? WHERE " +
"XMLCast(XMLQuery('/PO/PONO/text()'" +
" PASSING value(xmltab) RETURNING CONTENT)" +
" AS NUMBER)" +
"= 200");
stmt.setObject(1,xt); // bind the XMLType instance
stmt.execute();
conn.commit();
System.out.println("PurchaseOrder 200 Updated!");
}
//delete PurchaseOrder 1001
s.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);
}
}
SELECT x.xpo.getCLOBVal() FROM po_xml x;
例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-10 JDBCを使用したXMLType列の操作
import java.sql.*;
import java.io.*;
import java.net.*;
import java.util.*;
import oracle.xml.parser.v2.*;
import oracle.xml.parser.schema.*;
import org.xml.sax.*;
import org.w3c.dom.*;
import oracle.xml.sql.dataset.*;
import oracle.xml.sql.query.*;
import oracle.xml.sql.docgen.*;
import oracle.xml.sql.*;
import oracle.jdbc.driver.*;
import oracle.sql.*;
import oracle.xdb.XMLType;
public class tkxmtpk1
{
static String conStr = "jdbc:oracle:oci8:@";
static String user = "tpjc";
static String pass = "tpjc";
static String qryStr = "select x.resume from t1 x where id<3";
static String xslStr =
"<?xml version='1.0'?> " +
"<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1" +
"999/XSL/Transform'> " +
"<xsl:template match='ROOT'> " +
"<xsl:apply-templates/> " +
"</xsl:template> " +
"<xsl:template match='NAME'> " +
"<html> " +
" <body> " +
" This is Test " +
" </body> " +
"</html> " +
"</xsl:template> " +
"</xsl:stylesheet>";
static void parseArg(String args[])
{
conStr = (args.length >= 1 ? args[0]:conStr);
user = (args.length >= 2 ? args[1].substring(0, args[1].indexOf("/")):user);
pass = (args.length >= 2 ? args[1].substring(args[1].indexOf("/")+1):pass);
qryStr = (args.length >= 3 ? args[2]:qryStr);
}
/**
* Print the byte array contents
*/
static void showValue(byte[] bytes) throws SQLException
{
if (bytes == null)
System.out.println("null");
else if (bytes.length == 0)
System.out.println("empty");
else
{
for(int i=0; i<bytes.length; i++)
System.out.print((bytes[i]&0xff)+" ");
System.out.println();
}
}
public static void main(String args[]) throws Exception
{
tkxmjnd1 util = new tkxmjnd1();
try
{
if(args != null)
parseArg(args);
// System.out.println("conStr=" + conStr);
System.out.println("user/pass=" + user + "/" +pass );
System.out.println("qryStr=" + qryStr);
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection(conStr, user, pass);
Statement s = conn.createStatement();
ResultSet rset = s.executeQuery(qryStr);
OracleResultSet orset = (OracleResultSet) rset;
OPAQUE xml;
while(orset.next())
{
oracle.xdb.XMLType xt = (oracle.xdb.XMLType)(orset.getObject(1));
System.out.println("Testing getDOM() ...");
Document doc = xt.getDOM();
util.printDocument(doc);
System.out.println("Testing getBytesValue() ...");
showValue(xt.getBytesValue());
System.out.println("Testing existsNode() ...");
try
{
System.out.println("existsNode(/)" + xt.existsNode("/", null));
}
catch (SQLException e)
{
System.out.println("Thin driver Expected exception: " + e);
}
System.out.println("Testing extract() ...");
try
{
XMLType xt1 = xt.extract("/RESUME", null);
System.out.println("extract RESUME: " + xt1.getStringVal());
System.out.println("should be Fragment: " + xt1.isFragment());
}
catch (SQLException e)
{
System.out.println("Thin driver Expected exception: " + e);
}
System.out.println("Testing isFragment() ...");
try
{
System.out.println("isFragment = " + xt.isFragment());
}
catch (SQLException e)
{
System.out.println("Thin driver Expected exception: " + e);
}
System.out.println("Testing isSchemaValid() ...");
try
{
System.out.println("isSchemaValid(): " +
xt.isSchemaValid(null,"RES UME"));
}
catch (SQLException e)
{
System.out.println("Thin driver Expected exception: " + e);
}
System.out.println("Testing transform() ...");
System.out.println("XSLDOC: \n" + xslStr + "\n");
try
{
/* XMLType xslDoc = XMLType.createXML(conn, xslStr);
System.out.println("XSLDOC Generated");
System.out.println("After transformation:\n" +
(xt.transform(xslDoc,
null)).getStringVal());
*/
System.out.println("After transformation:\n" +
(xt.transform(null,
null)).getStringVal());
}
catch (SQLException e)
{
System.out.println("Thin driver Expected exception: " + e);
}
System.out.println("Testing createXML(conn, doc) ...");
try
{
XMLType xt1 = XMLType.createXML(conn, doc);
System.out.println(xt1.getStringVal());
}
catch (SQLException e)
{
System.out.println("Got exception: " + e);
}
}
}
catch(Exception e)
{
e.printStackTrace(System.out);
}
}
}
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のCLOBオブジェクトを使用して大規模なXML文書を保持することで回避できます。例13-11に、このテクニックを使用するコードを示します。これはXMLTypeメソッドのinsertXML()を定義します。これを使用して、大規模なXML文書が表poTableのXMLTypeの列purchaseOrderに挿入されます。XMLType表の場合も同じ方法を使用できます。
メソッドinsertXML()はXML文書を含むCLOBオブジェクトを使用します。CLOBオブジェクトは、クライアント側でクラスoracle.sql.CLOBを使用して作成されます。このクラスは、Oracle JDBC Driverによる標準JDBCインタフェースjava.sql.Clobの実装です。メソッドinsertXML()はCLOBオブジェクトをJDBCのプリコンパイルされたSQL文にバインドします。これによりデータがXMLType列に挿入されます。
insertXML()を使用するための前提条件は、次のとおりです。
Oracle Databaseがリリース9.2.0.1以上であること。
ターゲット・データベース表が存在すること。例を実行する前に、次のSQLを実行してください。
CREATE TABLE poTable (purchaseOrder XMLType);
XMLTypeメソッドのinsertXML()の仮パラメータは、次のとおりです。
xmlData - XMLType列に挿入するXMLデータ
conn - データベース接続オブジェクト(Oracle Connection Object)
JavaメソッドinsertXML()は、メソッドgetCLOB()をコールして、XMLデータを格納するCLOBオブジェクトを作成して戻します。getCLOB()メソッドの仮パラメータは例13-12で定義され、次のとおりです。
xmlData - XMLType列に挿入するXMLデータ
conn - データベース接続オブジェクト(Oracle Connection Object)
関連項目:
『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』
例13-11 JavaメソッドinsertXML()
... import oracle.sql.CLOB; import java.sql.Connection; import java.sql.SQLException; import java.sql.PreparedStatement; ... private void insertXML(String xmlData, Connection conn) { CLOB clob = null; String query; // Initialize statement Object PreparedStatement pstmt = null; try { query = "INSERT INTO potable (purchaseOrder) VALUES (XMLType(?)) "; // Get the statement Object pstmt = conn.prepareStatement(query); // xmlData is the string that contains the XML Data. // Get the CLOB object. clob = getCLOB(xmlData, conn); // Bind this CLOB with the prepared Statement pstmt.setObject(1, clob); // Execute the Prepared Statement if (pstmt.executeUpdate () == 1) { System.out.println ("Successfully inserted a Purchase Order"); } } catch(SQLException sqlexp) { sqlexp.printStackTrace(); } catch(Exception exp) { exp.printStackTrace(); } }
例13-12 JavaメソッドgetCLOB()
...
import oracle.sql.CLOB;
import java.sql.Connection;
import java.sql.SQLException;
import java.io.Writer;
...
private CLOB getCLOB(String xmlData, Connection conn) throws SQLException
{
CLOB tempClob = null;
try
{
// If the temporary CLOB has not yet been created, create one
tempClob = CLOB.createTemporary(conn, true, CLOB.DURATION_SESSION);
// Open the temporary CLOB in readwrite mode, to enable writing
tempClob.open(CLOB.MODE_READWRITE);
// Get the output stream to write
Writer tempClobWriter = tempClob.getCharacterOutputStream();
// Write the data into the temporary CLOB
tempClobWriter.write(xmlData);
// Flush and close the stream
tempClobWriter.flush();
tempClobWriter.close();
// Close the temporary CLOB
tempClob.close();
}
catch(SQLException sqlexp)
{
tempClob.freeTemporary();
sqlexp.printStackTrace();
}
catch(Exception exp)
{
tempClob.freeTemporary();
exp.printStackTrace();
}
return tempClob;
}
Java DOM API for XMLTypeは、XMLオブジェクトの子およびプロパティ(名前、名前空間など)を取得するために、文書内でのディープ検索およびシャロウ検索をサポートします。これにより、アプリケーションはその場で(動的に)作成するなど、XML文書をプログラムで作成できます。そのような文書は、登録されたXML Schemaに準拠することもあれば、しないこともあります。
Java API for XMLTypeはDOM 2.0勧告に準拠し、名前空間を認識します。
JavaクラスXMLDocumentおよびXDBDocument(非推奨)は、W3Cドキュメント・オブジェクト・モデル(DOM)・インタフェースのインスタンスです。このドキュメント・インタフェースからドキュメントの要素にアクセスすると、W3CのDOM勧告に指定されたすべての操作を実行できます。DOMは、次のものに対して機能します。
XML Schemaに基づく、基づかないに関係なく、あらゆる種類のXML文書
文書で使用される次のいずれかの形式の基礎となる記憶域
バイナリ・ラージ・オブジェクト(Binary Large Object: BLOB)
オブジェクト・リレーショナル
Java DOM APIを使用してOracle XML DBからXMLデータを取得する場合:
接続がThinの場合は、XMLDocumentインスタンスを取得します。
接続がThickまたはkprbの場合は、getDOM()メソッドでXDBDocumentインスタンスを、getDocument()メソッドでXMLDocumentインスタンスを取得します。getDOM()メソッドとXDBDocumentクラスは非推奨になりました。
アプリケーションのセキュリティ・ポリシーを実装するためにMS Windows上でJavaセキュリティ・マネージャ(クラスSecurityManager)を使用する場合は、Thick接続でJava DOM API for XMLTypeを使用するために、特定の権限をセキュリティ・ポリシー・ファイルに追加する必要があります。
例13-13では、このようなポリシー・ファイルの内容を示しています。ここで、c:\myworkspaceはOracle XML DBに関連するJARを含むワークスペース・フォルダです。(ポリシー・ファイルは、同じフォルダにある必要があります。)
例13-13で使用しているライブラリは、orageneric12およびoraxml12です。最後の2文字(ここでは12)は、データベースのメジャー・リリース番号に対応している必要があります(したがって、たとえばOracle Database 13 リリース2の場合、orageneric13とoraxml13を使用します)。
ポリシー・ファイルを作成すると、次のコマンドライン・スイッチを使用してプログラムを呼び出すことができます。
-Djava.security.manager=default -Djava.security.policy=c:\myworkspace\ojdbc.policy
例13-13 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";
}
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-14では、Java DOM API for XMLTypeを使用してDOMオブジェクトを作成し、関連するXML Schemaで指定された形式で格納します。この例では、XML Schemaに対する検証は示されていません。
例13-14 Java DOM APIを使用したDOMオブジェクトの作成
import oracle.xdb.XMLType;
...
OraclePreparedStatement stmt =
(OraclePreparedStatement) conn.prepareStatement(
"update po_xml_XMLTypetab set poDoc = ? ");
// the second argument is a string
String poString = "<PO><PONO>200</PONO><PNAME>PO_2</PNAME></PO>";
XMLType poXML = XMLType.createXML(conn, poString);
Document poDOM = (Document)poXML.getDOM();
Element rootElem = poDOM.createElement("PO");
poDOM.insertBefore(poDOM, rootElem, null);
// now bind the string..
stmt.setObject(1,poXML);
stmt.execute();
XMLTypeインスタンスは、oracle.xdb.XMLTypeによってJavaで表現されます。XMLTypeインスタンスがJDBCまたはSQLJのクライアントを使用してフェッチされると、このインスタンスは提供されたXMLTypeクラスのオブジェクトとして自動的に明示されます。
このクラスのオブジェクトは、データ操作言語(DML)文の値としてバウンドできます。通常、この値はXMLTypeです。
Oracle XML DBは、W3CのDOMレベル2勧告をサポートします。また、アプリケーションとOracle XML Developer's Kit for Javaの相互作用を容易にするOracle固有の拡張機能も提供します。Java DOM API for XMLTypeでは、W3C DOMインタフェースを実装するクラスが提供されます。
Oracleの拡張機能のリストは、次のURLを参照してください。
http://www.oracle.com/technetwork/database-features/xmldb/overview/index.html
XMLDocumentは、インスタンス化されたXML文書用のDOMを表すクラスです。Document引数を取るXMLTypeコンストラクタを使用して、XML文書からXMLTypeインスタンスを取得できます。
XMLType createXML(Connection conn, Document domdoc)
表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 |
Oracle Database 11gリリース1より前のリリースで使用されていたXMLTypeのJava DOM APIのいくつかのクラスとメソッドは、非推奨になったか、サポートが停止されました。
Oracle Database 9i (9.2.0.1)のマニュアルには次のメソッドに関する説明が含まれていますが、サポートされなくなりました。
XDBDocument.getElementByID
XDBDocument.importNode
XDBNode.normalize
XDBNode.isSupported
XDBDomImplementation.hasFeature
また、Oracle Database 11gリリース1以前は、oracle.xdb.domパッケージの異なるAPIがJava DOMに使用されていました。非推奨になったAPIの詳細は、該当リリースのドキュメントを参照してください。oracle.xdb.domの次のクラスは、非推奨です。かわりにoracle.xml.parser.v2クラスを使用してください。
XDBAttribute - XMLAttrを使用
XDBBinaryDocument
XDBCData - XMLCDATAを使用
XDBComment - XMLCommentを使用
XDBDocFragment - XMLDocumentFragmentを使用
XDBDocument - XMLDocumentを使用
XDBDocumentType - DTDを使用
XDBDOMException - XMLDomExceptionを使用
XDBDomImplementation - XMLDomImplementationを使用
XDBElement - XMLElementを使用
XDBEntity - XMLEntityを使用
XDBEntityReference - XMLEntityReferenceを使用
XDBNamedNodeMap - XMLAttrListを使用
XDBNode - XMLNodeを使用
XDBNodeList - NodeListを使用
XDBNotation - XMLNotationを使用
XDBProcInst - XMLPIを使用
XDBText - XMLTextを使用
XMLType表または列からデータを取得し、そこからJava XMLDocumentインスタンスを取得します。Java DOM API for XMLTypeを使用して、データのDOMツリーの要素を操作します。
図13-1に、Java DOM API for XMLTypeの使用方法を示します脚注1。次の手順を実行します。
XMLType表または表のXMLType列からXMLデータを取り出します。XMLデータをフェッチすると、OracleによってXMLTypeインスタンスが作成されます。これにより、getDocument()メソッドを使用してXMLDocumentインスタンスを取得できます。
Java DOM API for XMLTypeを使用してDOMツリーの要素を操作します。変更されたデータはXMLTypeインスタンスに格納されますが、データはJDBC更新を使用して戻されます。
XMLTypeおよびXMLDocumentインスタンスは、各クラスでclose()メソッドを使用してクローズする必要があります。クローズすると、保持されていた基礎となるメモリーがすべて解放されます。
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では拡張され、任意のサイズのテキスト・ノード値およびバイナリ・ノード値をサポートしています。
関連項目:
大規模ノードにおけるPL/SQLの使用方法の詳細は、「DBMS_XMLDOMを使用した大規模ノード処理」を参照してください。
非推奨のXDBNodeクラスおよびXDBAttributeクラスの詳細は、「非推奨またはサポート外になったXMLTypeのクラスとメソッドのJava DOM API」を参照してください。
Java String、Reader、およびWriterデータはすべてUCS2で表現されます。これは、データベース・キャラクタ・セットと同じではない場合があります。また、ノード文字データはキャラクタ・セットIDでタグ付けされており、ノード値が移入するときに設定されます。
次に示すoracle.xml.parser.v2.XMLNode.javaのメソッドにより、サイズが64KBを超えるノードにアクセスできます。リーフ・ノード(属性、PI、CDATAなど)ではないノードを取得または設定しようとすると、これらのAPIにより例外が発生します。また、その値を実際に書き込み、ノードへのストリーム・アクセス状態を維持する場合に使用するリソースを解放するclose()を使用してください。
メソッド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
}
...
このモデルでは、プッシュ・モードのパーサーを使用して、DOMノードの値を取得します。Oracle XML DBでは、パーサーによって読み取られた出力ストリームにノード・データを書き込みます。
バイナリ出力ストリームの場合:
public void getNodeValueAsBinaryStream (java.io.OutputStream pushValue)
throws java.io.IOException,
DOMException;
pushValueで指定されるjava.io.OutputStreamの状態はopenである必要があります。ノードのデータ型はRAWまたはBLOBである必要があります。それ以外の場合は、IOExceptionが発生します。ノード・バイナリ・データはOutputStreamのwrite()メソッドを使用してpushValueに書き込まれ、ノード値が完全にストリームに書き込まれるとclose()メソッドがコールされます。
文字出力ストリームの場合:
public void getNodeValueAsCharacterStream (java.io.Writer pushValue)
throws java.io.IOException,
DOMException;
pushValueで指定されるjava.io.Writerの状態はopenである必要があります。ノードのデータ型が文字でもCLOBでもない場合、まずデータは文字に変換されます。常に文字形式のノード・データは必要に応じてUCS2に変換され、java.io.Writerにプッシュされます。
このモデルでは、取出しモードのパーサーを使用して、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のバイナリ・データ全体がInputStreamのread()メソッドを使用して読み取られ、ノード値を置換します。
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からノードのキャラクタ・セットに変換されます。
このモデルでは、プッシュ・モードのパーサーを使用して、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 Database XML Java API Reference』
大規模ノードのためのC関数の詳細は、Oracle Database XML C APIリファレンスを参照してください。
Oracle XML DBはwriterまたはOutputStreamを作成し、それをノード値が完全に書き込まれるまで繰り返しwrite()メソッドをコールするユーザーに渡します。新規ノード値は、ユーザーがclose()メソッドをコールするときのみ反映されます。
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データを読書きするためには、次の手順を実行する必要があります。
メタデータのコンテキスト・インスタンスを作成します。
このコンテキストを、データベース内のバイナリXMLデータにアクセスするために使用するデータ接続に関連付けます。データ接続は、専用接続でも接続プールでもかまいません。クラスjava.sql.ConnectionのメソッドgetDedicatedConn()およびgetConnPool()を使用して、それらの接続の型に応じて、これら2つの接続型へのハンドルを取得します。
すると、アプリケーションがデータ接続上でバイナリXMLデータをエンコードまたはデコードする必要がある場合、それに必要なメタデータが自動的にフェッチされます。一連の動作の全体は次のとおりです。
クラスjava.sql.ConnectionにXMLデータ接続オブジェクトを作成します。
パッケージoracle.xml.binxml内のメソッドBinXMLMetadataProviderFactory.createDBMetadataProvider()を使用して、必要に応じて1つ以上のメタデータ・コンテキストを作成します。メタデータ・コンテキストは、メタデータ・リポジトリと呼ばれることもあります。メタデータ・コンテキストは、専用接続または接続プールから作成することができます。
メタデータ・コンテキストをバイナリXMLデータ接続に関連付けます。これには、パッケージoracle.xml.binxml内のメソッドDBBinXMLMetadataProvider.associateDataConnection()を使用します。
(オプション) XMLデータがデータベース外に由来するものの場合は、メソッドoracle.xdb.XMLType.setFormatPref()を使用して、データベースに送信されるXMLデータがバイナリXML形式でエンコードされるように指定します。これは、DOM文書(クラスoracle.xdb.XMLType)に適用されます。バイナリXMLを指定しない場合、データはテキストとしてデータベースに送信されます。
通常のJavaメソッドを使用して、データベースに対してXMLデータを読書きします。バイナリXML文書のエンコードやデコードに必要なときは常に、メタデータ・コンテキストを使用して、必要なメタデータが自動的にフェッチされます。
Java DOM API for XMLを使用して、クライアント・レベルのXMLデータに対して操作します。
例13-15に、これを示します。
関連項目:
『Oracle XML Developer's Kitプログラマーズ・ガイド』
例13-15 バイナリXMLでのJava DOM APIの使用
import java.sql.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.OracleDataSource;
import oracle.xdb.XMLType;
import oracle.xml.binxml.*;
class tdadxdbxdb11jav001
{
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 conn = 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(conn);
// Query XML data stored in XMLType column as binary XML
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery("SELECT doc FROM po_binxmltab");
// Get the XMLType object
while (rset.next())
{
XMLType xmlobj = (XMLType) rset.getObject(1);
// Perform XMLType operation
String xmlvalue = xmlobj.getStringVal();
System.out.println(xmlvalue);
}
// Close result set, statement, and connection
rset.close();
stmt.close();
conn.close();
System.out.println("Completed Binary XML Java Example");
}
}
脚注の凡例
脚注1:ここでは、XMLデータがXML Schemaに登録済であり、XMLTypeの列に格納されていると想定しています。