오라클은 Oracle8i 플랫폼에 JDK와 호환되는 완벽한 표준 Java 가상머신과 JDBC를 포함하여 확장성이 매우 높은 서버 환경을 제공하고 있다. 오라클은 이러한 서버 상에서의 XML 처리를 지원하기 위해 XML 파서, XLST 처리기, XML Search Engine interMedia 을 포함하여 XML 애플리케이션 개발에 유연함을 제공하고 있다. 그 외에도 오라클은 XML 지원 기능을 강화한 XDK (XML Developer’s Kit), XSU (XML SQL Utility), iFS (internet File System), Jdeveloper, WebDB 등의 제품을 통해 XML처리 애플리케이션 개발을 단순화할 수 있도록 지원하고 있다.

XDK (XML Developer’s Kit) 는 XML 컴포넌트 라이브러리와 유틸리티들로 구성된 것으로, XML을 이용한 애플리케이션 개발을 용이하게 하기 위해서 Java, C, C++, 그리고 PL/SQL 등으로 구현된 툴킷이다.

현재까지 오라클에서 제공하는 XDK는 다음과 같다.

Using XML in Oracle Database Applications

● XML Parsers and XSL Processors (Java, C, C++, and PL/SQL)

● XML Class Generators (Java and C++)

● XML SQL Utility for Java

● XSQL Servlet

● XML Transviewer Beans

XML Parsers

XML 파서

XML 파서 (parser) 는 C, C++, PL/SQL, 그리고, Java로 구현된 버전이 있다. 이 중 Java로 구현된 XML 파서는 Oracle8i에 내장되어 있고, 같이 내장된 Java 가상머신에 의해 바로 실행할 수 있다. 또 XML 파서는 XML 1.0 스펙을 지원하고 DOM (Document Object Model) 과 SAX (Simple API for XML) 인터페이스를 제공한다.

DOM and SAX APIs

그림1

DOM 인터페이스는 XML을 파싱하여 <그림 1>과 같이 메모리에 상주하는 트리를 만들어 준다. 따라서, 이를 이용하면, 트리를 검색하고 조작하는 애플리케이션 개발이 용이하다. 예를 들어, 엘리먼트들을 재순서화한다든가 새로운 엘리먼트 또는 속성을 추가한다든가 또는 엘리먼트의 이름을 재명명하는 등의 작업이 용이하다. |리스트 1|

<리스트 1> emp.xml

<?xml version="1.0" encoding="EUC-KR"?>

<!DOCTYPE EMPLIST[

<!ELEMENT EMPLIST (EMP+)>

<!ELEMENT EMP (ENAME)>

<!ELEMENT ENAME (#PCDATA)>

<!ATTLIST ENAME id CDATA #IMPLIED>

]>

<EMPLIST>

<EMP>

<ENAME id="1">MARTIN</ENAME>

</EMP>

<EMP>

<ENAME>SCOTT</ENAME>

</EMP>

</EMPLIST>

하지만, 트리가 메모리에 상주하게 되므로 크기가 매우 큰 XML 문서의 경우는 SAX 인터페이스를 이용하는 것이 좋다. SAX 인터페이스는 이벤트를 통해서 XML 문서를 처리한다. 이벤트는 엘리먼트의 시작과 끝 또는 컨텐트의 시작과 끝 등을 의미한다. 따라서, SAX 인터페이스를 이용하여 애플리케이션을 개발하는 것은 각 이벤트가 발생하였을 때 처리해 주는 프로그램을 개발하는 것을 의미한다. 단, SAX는 이벤트 방식이기 때문에 검색이나 조작 연산을 사용할 때는 비효율적이다.

또한, XML 파서는 XML 이름 공간, 유효성과 비유효성 모드를 지원한다. 그리고, XML 파서의 버전 2.0은 XSLT 처리기를 내장하고 있어서 XML 문서들의 XML간 변환 및 HTML로의 변환에 이용할 수 있다.

family.xml file 내용

<?xml version="1.0" standalone="no"?>

<!DOCTYPE family SYSTEM "family.dtd">

<family lastname="Smith">

<member memberid="m1">Sarah</member>

<member memberid="m2">Bob</member>

<member memberid="m3" mom="m1" dad="m2">Joanne</member>

<member memberid="m4" mom="m1" dad="m2">Jim</member>

</family>

family.DTD file 내용

<!ELEMENT family (member*)>

<!ATTLIST family lastname CDATA #REQUIRED>

<!ELEMENT member (#PCDATA)>

<!ATTLIST member memberid ID #REQUIRED>

<!ATTLIST member dad IDREF #IMPLIED>

<!ATTLIST member mom IDREF #IMPLIED>

// This file demonstates a simple use of the parser and DOM API.

// The XML file that is given to the application is parsed and the

// elements and attributes in the document are printed.

// The use of setting the parser options is demonstrated.

//

import java.io.*;

import java.net.*;

import org.w3c.dom.*;

import org.w3c.dom.Node;

import oracle.xml.parser.v2.DOMParser;

public class DOMSample

{

static public void main(String[] argv)

{

try

{

if (argv.length != 1)

{

// Must pass in the name of the XML file.

System.err.println("Usage: java DOMSample filename");

System.exit(1);

}

// Get an instance of the parser

DOMParser parser = new DOMParser();

// Generate a URL from the filename.

URL url = createURL(argv[0]);

// Set various parser options: validation on,

// warnings shown, error stream set to stderr.

parser.setErrorStream(System.err);

parser.setValidationMode(true);

parser.showWarnings(true);

// Parse the document.

parser.parse(url);

// Obtain the document.

Document doc = parser.getDocument();

// Print document elements

System.out.print("The elements are: ");

printElements(doc);

// Print document element attributes

System.out.println("The attributes of each element are: ");

printElementAttributes(doc);

}

catch (Exception e)

{

System.out.println(e.toString());

}

}

static void printElements(Document doc)

{

NodeList nl = doc.getElementsByTagName("*");

Node n;

for (int i=0; i<nl.getLength(); i++)

{

n = nl.item(i);

System.out.print(n.getNodeName() + " ");

}

System.out.println();

}

static void printElementAttributes(Document doc)

{

NodeList nl = doc.getElementsByTagName("*");

Element e;

Node n;

NamedNodeMap nnm;

String attrname;

String attrval;

int i, len;

len = nl.getLength();

for (int j=0; j < len; j++)

{

e = (Element)nl.item(j);

System.out.println(e.getTagName() + ":");

nnm = e.getAttributes();

if (nnm != null)

{

for (i=0; i<nnm.getLength(); i++)

{

n = nnm.item(i);

attrname = n.getNodeName();

attrval = n.getNodeValue();

System.out.print(" " + attrname + " = " + attrval);

}

}

System.out.println();

}

}

static URL createURL(String fileName)

{

URL url = null;

try

{

url = new URL(fileName);

}

catch (MalformedURLException ex)

{

File f = new File(fileName);

try

{

String path = f.getAbsolutePath();

String fs = System.getProperty("file.separator");

if (fs.length() == 1)

{

char sep = fs.charAt(0);

if (sep != '/')

path = path.replace(sep, '/');

if (path.charAt(0) != '/')

path = '/' + path;

}

path = "file://" + path;

url = new URL(path);

}

catch (MalformedURLException e)

{

System.out.println("Cannot create url for: " + fileName);

System.exit(0);

}

}

return url;

}

}

C:\orautil>java DOMSample family.xml

The elements are: family member member member member

The attributes of each element are:

family:

lastname = Smith

member:

memberid = m1

member:

memberid = m2

member:

memberid = m3 mom = m1 dad = m2

member:

memberid = m4 mom = m1 dad = m2

// This file demonstates a simple use of the parser and SAX API.

// The XML file that is given to the application is parsed and

// prints out some information about the contents of this file.

//

import org.xml.sax.*;

import java.io.*;

import java.net.*;

import oracle.xml.parser.v2.*;

public class SAXSample extends HandlerBase

{

// Store the locator

Locator locator;

static public void main(String[] argv)

{

try

{

if (argv.length != 1)

{

// Must pass in the name of the XML file.

System.err.println("Usage: SAXSample filename");

System.exit(1);

}

// Create a new handler for the parser

SAXSample sample = new SAXSample();

// Get an instance of the parser

Parser parser = new SAXParser();

// Set Handlers in the parser

parser.setDocumentHandler(sample);

parser.setEntityResolver(sample);

parser.setDTDHandler(sample);

parser.setErrorHandler(sample);

// Convert file to URL and parse

try

{

parser.parse(fileToURL(new File(argv[0])).toString());

}

catch (SAXParseException e)

{

System.out.println(e.getMessage());

}

catch (SAXException e)

{

System.out.println(e.getMessage());

}

}

catch (Exception e)

{

System.out.println(e.toString());

}

}

static URL fileToURL(File file)

{

String path = file.getAbsolutePath();

String fSep = System.getProperty("file.separator");

if (fSep != null && fSep.length() == 1)

path = path.replace(fSep.charAt(0), '/');

if (path.length() > 0 && path.charAt(0) != '/')

path = '/' + path;

try

{

return new URL("file", null, path);

}

catch (java.net.MalformedURLException e)

{

throw new Error("unexpected MalformedURLException");

}

}

//////////////////////////////////////////////////////////////////////

// Sample implementation of DocumentHandler interface.

//////////////////////////////////////////////////////////////////////

public void setDocumentLocator (Locator locator)

{

System.out.println("SetDocumentLocator:");

this.locator = locator;

}

public void startDocument()

{

System.out.println("StartDocument");

}

public void endDocument() throws SAXException

{

System.out.println("EndDocument");

}

public void startElement(String name, AttributeList atts)

throws SAXException

{

System.out.println("StartElement:"+name);

for (int i=0;i<atts.getLength();i++)

{

String aname = atts.getName(i);

String type = atts.getType(i);

String value = atts.getValue(i);

System.out.println("   "+aname+"("+type+")"+"="+value);

}

}

public void endElement(String name) throws SAXException

{

System.out.println("EndElement:"+name);

}

public void characters(char[] cbuf, int start, int len)

{

System.out.print("Characters:");

System.out.println(new String(cbuf,start,len));

}

public void ignorableWhitespace(char[] cbuf, int start, int len)

{

System.out.println("IgnorableWhiteSpace");

}

public void processingInstruction(String target, String data)

throws SAXException

{

System.out.println("ProcessingInstruction:"+target+" "+data);

}

//////////////////////////////////////////////////////////////////////

// Sample implementation of the EntityResolver interface.

//////////////////////////////////////////////////////////////////////

public InputSource resolveEntity (String publicId, String systemId)

throws SAXException

{

System.out.println("ResolveEntity:"+publicId+" "+systemId);

System.out.println("Locator:"+locator.getPublicId()+" "+

locator.getSystemId()+

" "+locator.getLineNumber()+" "+locator.getColumnNumber());

return null;

}

//////////////////////////////////////////////////////////////////////

// Sample implementation of the DTDHandler interface.

//////////////////////////////////////////////////////////////////////

public void notationDecl (String name, String publicId, String systemId)

{

System.out.println("NotationDecl:"+name+" "+publicId+" "+systemId);

}

public void unparsedEntityDecl (String name, String publicId,

String systemId, String notationName)

{

System.out.println("UnparsedEntityDecl:"+name + " "+publicId+" "+

systemId+" "+notationName);

}

//////////////////////////////////////////////////////////////////////

// Sample implementation of the ErrorHandler interface.

//////////////////////////////////////////////////////////////////////

public void warning (SAXParseException e)

throws SAXException

{

System.out.println("Warning:"+e.getMessage());

}

public void error (SAXParseException e)

throws SAXException

{

throw new SAXException(e.getMessage());

}

public void fatalError (SAXParseException e)

throws SAXException

{

System.out.println("Fatal error");

throw new SAXException(e.getMessage());

}

}

C:\orautil>java SAXSample family.xml

SetDocumentLocator:

StartDocument

ResolveEntity:null file:/C:/orautil/family.dtd

Locator:null file:/C:/orautil/family.xml 2 38

StartElement:family

lastname(CDATA)=Smith

IgnorableWhiteSpace

StartElement:member

memberid(ID)=m1

Characters:Sarah

EndElement:member

IgnorableWhiteSpace

StartElement:member

memberid(ID)=m2

Characters:Bob

EndElement:member

IgnorableWhiteSpace

StartElement:member

memberid(ID)=m3

mom(CDATA)=m1

dad(CDATA)=m2

Characters:Joanne

EndElement:member

IgnorableWhiteSpace

StartElement:member

memberid(ID)=m4

mom(CDATA)=m1

dad(CDATA)=m2

Characters:Jim

EndElement:member

IgnorableWhiteSpace

EndElement:family

EndDocument

C:\orautil>

XSL Transformation Support

The v2 versions of the XML Parsers include an integrated XSL Transformation (XSLT) Processor for transforming XML data using XSL stylesheets. Using the XSLT processor, you can transform XML documents from XML to XML, HTML, or virtually any other text-based format.

XML Class Generator for Java

<그림2> XML Class Generator for Java의 동작 과정

XML Class Generator for Java는 XML의 DTD (Document Type Definition) 로부터 Java 소스 코드를 생성해 주는 툴이다. 이 툴은 약속된 DTD에 기반을 두고 XML 포맷의 메시지를 다른 애플리케이션에 보내려는 애플리케이션을 개발할 때 유용하다.

XML Class Generator는 XML 파서와 함께 동작한다 |그림 2|.먼저, XML 파서는 DTD를 입력으로 받고, DTD를 파싱하여 XML Class Generator에게 전달한다. XML Class Generator는 파싱된 DTD의 각 엘리먼트별로 하나의 클래스를 생성한다. 이렇게 생성된 클래스들을 가지고 입력된 DTD에 유효한 XML 문서를 만들어 내는 애플리케이션을 개발할 수 있게 된다. XML Class Generator for C++도 마찬가지로 동작한다.

현재 오라클은 XML Schema Language 중 XML Schema를 표준화하는 작업에 참여하고 있다. DTD는 이미 표준화된 XML Schema Language이다. 하지만, DTD가 데이타 타입을 정의할 수 없다는 가장 큰 이유 때문에 데이타베이스에 적용하기 힘들다. 그래서, XML Schema를 표준으로 하여 XML 문서를 XML Schema에서 정의한 데이타 타입으로 저장할 수 있도록 지원하는 툴을 개발중인데, 그것이 XML Schema Processor for Java라는 툴이다 (현재 베타버전 테스트중).

XML Schema와 DTD의 또 다른 차이점은 DTD는 DTD 구성 문법이 따로 있는 반면에, XML Schema는 XML 문법을 그대로 사용하여 정의할 수 있다는 점이다. 현재, 오라클 iFS (internet File System) 제품에서 XML Schema를 이용하고 있다. XML Schema의 표준화 작업이 끝나는 대로 XML Schema Processor와 iFS 정식 버전이 출시될 것이다.

import java.io.*;

import java.net.*;

import oracle.xml.parser.*;

import oracle.xml.classgen.*;

import org.w3c.dom.Element;

/**

* Sample Class to uses XML Class Generator

*/

public class SampleMain

{

public SampleMain()

{

}

public static void main (String args[])

{

// validate arguments

if (args.length < 1)

{

System.out.println("Usage: java SampleMain "+

"[-root <rootName>] <fileName>");

System.out.println("fileName\t   Input file, XML document or " +

"external DTD file");

System.out.println("-root <rootName>   Name of the root Element " +

"(required if the input file is an external DTD)");

return ;

}

try // to open the XML File/ External DTD File

{

// instantiate the parser

XMLParser parser = new XMLParser();

if (args.length == 3)

parser.parseDTD(fileToURL(args[2]), args[1]);

else

parser.parse(fileToURL(args[0]));

XMLDocument doc = parser.getDocument();

DTD dtd = (DTD)doc.getDoctype();

String doctype_name = null;

if (args.length == 3)

{

doctype_name = args[1];

}

else

{

/* get the Root Element name from the XMLDocument*/

doctype_name = doc.getDocumentElement().getTagName();

}

// generate the Java files...

ClassGenerator generator = new ClassGenerator();

// set generate comments to true

generator.setGenerateComments(true);

// set output directory

generator.setOutputDirectory(".");

// set validating mode to true

generator.setValidationMode(true);

// generate java src

generator.generate(dtd, doctype_name);

}

catch (Exception e)

{

System.out.println ("XML Class Generator: Error " + e.toString());

e.printStackTrace();

}

}

static public URL fileToURL(String sfile)

{

File file = new File(sfile);

String path = file.getAbsolutePath();

String fSep = System.getProperty("file.separator");

if (fSep != null && fSep.length() == 1)

path = path.replace(fSep.charAt(0), '/');

if (path.length() > 0 && path.charAt(0) != '/')

path = '/' + path;

try

{

return new URL("file", null, path);

}

catch (java.net.MalformedURLException e)

{

/* According to the spec this could only happen if the file

protocol were not recognized. */

throw new Error("unexpected MalformedURLException");

}

}

}

TestWidl.java

import oracle.xml.classgen.*;

import oracle.xml.parser.*;

public class TestWidl

{

public static void main (String args[])

{

try

{

WIDL w1 = new WIDL();

DTD dtd = w1.getDTDNode();

w1.setNAME("WIDL1");

w1.setVERSION(WIDL.VERSION_1_0);

SERVICE s1 = new SERVICE("Service1", "Service_URL");

s1.setINPUT("File");

s1.setOUTPUT("File");

BINDING b1 = new BINDING("Binding1");

b1.setTYPE(BINDING.TYPE_INPUT);

BINDING b2 = new BINDING("Binding2");

b2.setTYPE(BINDING.TYPE_OUTPUT);

VARIABLE v1 = new VARIABLE("Variable1", VARIABLE.NULLOK_FALSE);

v1.setTYPE(VARIABLE.TYPE_STRING);

v1.setUSAGE(VARIABLE.USAGE_INTERNAL);

v1.setVALUE("value");

VARIABLE v2 = new VARIABLE("Variable2", VARIABLE.NULLOK_TRUE);

v2.setTYPE(VARIABLE.TYPE_STRING1);

v2.setUSAGE(VARIABLE.USAGE_HEADER);

VARIABLE v3 = new VARIABLE("Variable3", VARIABLE.NULLOK_FALSE);

v3.setTYPE(VARIABLE.TYPE_STRING2);

v3.setUSAGE(VARIABLE.USAGE_FUNCTION);

v3.setMASK("mask");

CONDITION c1 = new CONDITION("CRef1", "CMatch1");

c1.setSERVICE("Service1");

c1.setTYPE(CONDITION.TYPE_SUCCESS);

CONDITION c2 = new CONDITION("CRef2", "CMatch2");

c2.setTYPE(CONDITION.TYPE_RETRY);

CONDITION c3 = new CONDITION("CRef3", "CMatch3");

c3.setSERVICE("Service3");

c3.setTYPE(CONDITION.TYPE_FAILURE);

REGION r1 = new REGION("Region1", "Start", "End");

b1.addNode(r1);

b1.addNode(v1);

b1.addNode(c1);

b1.addNode(v2);

b2.addNode(c2);

b2.addNode(v3);

w1.addNode(s1);

w1.addNode(b1);

w1.addNode(b2);

w1.validateContent();

w1.print(System.out);

}

catch (Exception e)

{

System.out.println(e.toString());

e.printStackTrace();

}

}

}

C:\orautil>javac SampleMain.java

C:\orautil>java SampleMain Widl.xml

C:\orautil>javac *.java

C:\orautil>javac TestWidl.java

C:\orautil>java TestWidl

<?xml  version = '1.0' encoding = 'ASCII'?>

<!DOCTYPE WIDL SYSTEM "file:/C:/orautil/WIDL_dtd.txt">

<WIDL NAME="WIDL1" VERSION="1.0">

<SERVICE NAME="Service1" URL="Service_URL" INPUT="File" OUTPUT="File"/>

<BINDING NAME="Binding1" TYPE="Input">

<REGION NAME="Region1" START="Start" END="End"/>

<VARIABLE NAME="Variable1" NULLOK="False" TYPE="String" USAGE="Internal" V

ALUE="value"/>

<CONDITION REF="CRef1" MATCH="CMatch1" SERVICE="Service1" TYPE="Success"/>

<VARIABLE NAME="Variable2" NULLOK="True" TYPE="String1" USAGE="Header"/>

</BINDING>

<BINDING NAME="Binding2" TYPE="Output">

<CONDITION REF="CRef2" MATCH="CMatch2" TYPE="Retry"/>

<VARIABLE NAME="Variable3" NULLOK="False" TYPE="String2" USAGE="Function"

MASK="mask"/>

</BINDING>

</WIDL>

C:\orautil>

Writing XML to a Database Table

<그림3>XML 데이타를 데이타베이스에 저장

XML 문서의 구조가 잘 정의되어지고 자주 변경이 가해지는 경우는 XML 문서의 전체 또는 일부를 오라클의 객체-관계형 테이블 형태로 저장하는 것이 효율적이다. 물론, 다른 저장 방법으로 interMedia Text를 이용할 수도 있다. 이에 대한 설명과 비교는 interMedia Text에서 자세히 다루겠다.

오라클의 XSU (XML SQL Utility for java) 는 XML 문서의 전체 또는 일부를 객체-관계형 테이블로 사상하여 저장하는 기능과 함께 반대로 객체-관계형 테이블의 데이타를 검색하는 기능을 제공한다. 하지만, XML은 반구조적인 데이타 모델이고, 객체-관계형 테이블은 구조적 데이타 모델이기 때문에 XML 문서를 그대로 데이타베이스에 사상시키는 것은 자료의 손실을 초래한다. 따라서, XML은 XSLT 스타일시트를 통하거나 프로그래밍을 통해 자료의 손실이 발생하지 않도록 변환하는 것이 필요하다. 그러므로, XSU를 이용할 때는 자료가 손실되지 않도록 주의를 기울일 필요가 있다.

그러면, 앞서 설명한 XSU의 두 가지 기능을 예제를 통해서 살펴보자.

첫 번째 기능은 XML 데이타를 데이타베이스의 테이블로 사상하여 저장하는 기능으로, 그 구조는 |그림 3|과 같다.

XML 데이타가 Oracle8i에 저장될 때 XML 문서의 각 엘리먼트의 이름들은 Oracle8i의 테이블에서의 컬럼으로 사상된다. |리스트 2|의 예제 프로그램은 리스트 윗 부분의 emp.xml 파일을 입력으로 받아서 EMP 테이블에 사상하여 저장하는 프로그램이다.

리스트 2 ｃ XML 문서 저장프로그램

emp.xml :

<?xml version="1.0"?>

<ROWSET>

<ROW id="1">

<EMPNO>7654</EMPNO>

<ENAME>MARTIN</ENAME>

</ROW>

</ROWSET>

--------------------------------------------

import oracle.xml.sql.dml.*;

import java.sql.*;

import oracle.jdbc.driver.*;

import oracle.jdbc.*;

import java.net.*;

public class xmlwritedb

{

public static void main(String args[]) throws SQLException

{

String tabName = "EMP"; // Table into which to insert XML data

String fileName = "emp.xml"; // XML document filename

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

//JDBC 연결을 초기화한다.

Connection conn =

DriverManager.getConnection("jdbc:oracle:oci8:scott/tiger@");

// XML 데이타 "emp.xml"을 데이타베이스의 EMP 테이블로

// 사상하여 저장한다.

OracleXMLSave save = new OracleXMLSave(conn, tabName);

URL url = save.createURL(fileName);

int rowCount = save.insertXML(url);

System.out.println(" successfully inserted "+rowCount+

" rows into "+ tabName);

conn.close();

}

}

|리스트 2|의 예제 프로그램을 보면, OracleXMLSave 클래스의 insertXML 메소드를 통해 emp.xml을 저장하는 과정을 이해할 수 있다. 이 때, emp.xml은 어떤 XSLT도 지정하지 않았다. 따라서, 반드시 emp.xml은 <ROWSET>, <ROW> 그리고 <컬럼명> 순의 구조를 가지고 작성되어져야 한다.

Generating XML from Query Results

<그림4>질의어 결과로 XML 문서를 반환

두번째 기능은 SQL 질의어 결과 데이타를 XML 문서 (또는 텍스트 스트링이나 DOM) 로 구성하여 반환하는 기능이다. 그 구조는 <그림 4>와 같으며, |리스트 3| 은 그 예제 프로그램이다.

리스트 3 ｃ 질의어 결과를 XML로 반환하는 프로그램

import java.sql.*;

import java.math.*;

import oracle.xml.sql.query.*;

import oracle.jdbc.*;

import oracle.jdbc.driver.*;

public class xmlquerydb

{

public static void main(String args[]) throws SQLException

{

String tabName = "EMP";

String user = "scott/tiger";

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

//JDBC 연결을 초기화

Connection conn =

DriverManager.getConnection("jdbc:oracle:oci8:"+user+"@");

// OracleXMLQuery 생성 및 초기화

OracleXMLQuery qry = new OracleXMLQuery(conn,"select EMPNO,

ENAME from "+tabName );

// 생성될 XML 문서의 구조를 정의한다.

qry.setMaxRows(2); // set the maximum number of rows to be returned

qry.setRowsetTag("ROOTDOC"); // set the root document tag

qry.setRowTag("DBROW"); // sets the row separator tag

qry.setStyleSheet("emp.xsl"); // sets the stylesheet

// XML 문서를 텍스트 스트링으로 구성한다.

String xmlString = qry.getXMLString();

// 결과를 프린트한다.

System.out.println(" OUTPUT IS:\n"+xmlString);

}

}

|리스트 3|의 예제 프로그램을 보면, OracleXMLQuery 클래스가 SQL 질의어를 입력으로 받고 OracleXMLQuery 클래스의 다른 메소드들을 통해 결과로 생성할 XML 문서의 구조를 정의한 후에 getXMLString 메소드를 통해 XML 데이타를 텍스트 스트링으로 반환하는 과정을 알 수 있다. 현재까지는 데이타베이스와 XML 문서간의 구조적인 차이 때문에 자료 손실이 발생하지 않음을 프로그램 개발자가 책임져야 한다. 따라서, XSU를 이용할 때는 XML의 구조를 잘 정의해야 할 필요가 있다.

오라클의 데이타를 이용해서 XML문서를 생성한다.

import java.sql.*;

import java.math.*;

import oracle.xml.sql.query.*;

import oracle.jdbc.*;

import oracle.jdbc.driver.*;

public class samp1{

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

String tabName = "emp";

String user = "scott/tiger";

//오라클 드라이버를 Register에 등록한다.

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

//데이타베이스에 대한 접속을 얻는다.

Connection conn =

DriverManager.getConnection("jdbc:oracle:oci8:"+user+"@");

//Statementm객체를 생성

Statement stmt = conn.createStatement();

//sql 질의어를 수행하고, resultset을 구한다.

ResultSet rset = stmt.executeQuery("select * from "+tabName );

//xml에 대한 정보를 생성한다.

OracleXMLQuery qry =  new OracleXMLQuery(conn,rset);

//xml문서를 xmlstring객체에 저장한다.

String xmlString = qry.getXMLString();

System.out.println(" OUPUT IS:"+xmlString);

}

}

OUPUT IS :

<?xml version="1.0"?>

<ROWSET>

<ROW id="1">

<EMPNO>10</EMPNO>

<ENAME>Scott</ENAME>

</ROW>

</ROWSET>

connect scott/tiger

drop table xmltest_tab1;

create table xmltest_tab1 (EMPNO NUMBER(4), ENAME CHAR(10), JOB VARCHAR2(9));

<?xml version="1.0"?>

<ROWSET>

<ROW num="1">

<EMPNO>7369</EMPNO>

<ENAME>SMITH</ENAME>

<JOB>CLERK</JOB>

</ROW>

<ROW num="2">

<EMPNO>7499</EMPNO>

<ENAME>ALLEN</ENAME>

<JOB>SALESMAN</JOB>

</ROW>

<ROW num="3">

<EMPNO>7521</EMPNO>

<ENAME>WARD</ENAME>

<JOB>SALESMAN</JOB>

</ROW>

</ROWSET>

import oracle.xml.sql.dml.*;n

import java.sql.*;

import oracle.jdbc.driver.*;

import oracle.jdbc.*;

import java.net.*;

public class samp10

{

public static void main(String args[]) throws SQLException

{

String tabName = "XMLTEST_TAB1";	// table into which to insert

String fileName = "sampdoc.xml";	// file name containing the xml doc

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

//init a JDBC connection

Connection conn =

DriverManager.getConnection("jdbc:oracle:oci8:scott/tiger@");

OracleXMLSave sav = new OracleXMLSave(conn, tabName);

URL url = sav.createURL(fileName);

int rowCount = sav.insertXML(url);

System.out.println(" successfully inserted "+rowCount+

" rows into "+ tabName);

conn.close();

}

}

import java.sql.*;

import java.math.*;

import oracle.xml.sql.query.*;

import oracle.jdbc.*;

import oracle.jdbc.driver.*;

public class samp2{

public static void main(String args[]) throws SQLException

{

String tabName = "emp";

String user = "scott/tiger";

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

Connection conn =

DriverManager.getConnection("jdbc:oracle:oci8:"+user+"@");

OracleXMLQuery qry =  new OracleXMLQuery(conn,"select * from "+tabName );

qry.setMaxRows(2);

qry.setSkipRows(3);

qry.setRowsetTag("MYDOC");

qry.setRowTag("RECORD");

qry.setStyleSheet("my.xsl");

qry.setRowIdAttrName("cnt");

qry.useNullAttributeIndicator(true);

qry.setErrorTag("ERR");

String xmlString = qry.getXMLString();

System.out.println(" OUPUT IS:"+xmlString);  } }

OUPUT IS:

<?xml version="1.0"?>

<?xml-stylesheet href="my.xsl" type="text/xsl"?>

<MYDOC>

<RECORD CNT="4">

<EMPNO>7566</EMPNO>

<ENAME>JONES</ENAME>

<JOB>MANAGER</JOB>

<MGR>7839</MGR>

<HIREDATE>1981-04-02 00:00:00.0</HIREDATE>

<SAL>2975</SAL>

<COMM NULL="YES" />

<DEPTNO>20</DEPTNO>

</RECORD>

<RECORD CNT="5">

<EMPNO>7654</EMPNO>

<ENAME>MARTIN</ENAME>

<JOB>SALESMAN</JOB>

<MGR>7698</MGR>

<HIREDATE>1981-09-28 00:00:00.0</HIREDATE>

<SAL>1250</SAL>

<COMM>1400</COMM>

<DEPTNO>30</DEPTNO>

</RECORD>

</MYDOC>

interMedia Text

Oracle8i는 Oracle JServer, Java 가상머신 그리고 interMedia Text를 내장하고 있어서 Java와 XML을 포함한 인터넷 환경의 애플리케이션와 컴포넌트를 구동시킬 수 있다.

오라클에서는 XML 저장소로서의 기능을 3가지로 분류하여 지원하고 있다. 첫번째로 XML 문서 전체나 일부를 CLOB이나 BLOB 형으로 저장하는 기능이 있고, 둘째로 XML 문서를 태그에 따라 분류하여 테이블로 매핑시켜 저장하는 기능이 있으며, 마지막으로 이 두 가지 기능을 혼용한 기능이 있다. 첫 번째 기능은 interMedia Text를 이용하여 제공되고, 두 번째 기능은 앞서 설명한 XSU를 이용하여 제공된다.

데이타베이스에 CLOB이나 BLOB 형으로 저장된 모든 XML 문서 또는 문서의 일부분도 interMedia Text의 검색 엔진에 의해 인덱싱이 가능하다. interMedia Text는 Oracle8i가 개발자들에게 문서의 특정 섹션을 정확하게 찾도록 해주며, 이 단락은 문서내에서 XML 태그에 의해 내부적으로 정의된다. 검색은 SQL을 이용하여 구조화된 데이타와 인덱스된 문서 부분 모두를 포함하는 질의를 수행할 수 있다.

Oracle8.1.5 버전부터 interMedia Text에서 XML_SECTION_GROUP을 통해서 XML을 지원하였다. 하지만, 한글 미처리 문제와 이름공간 (namespace) 의 제한이 있었고 Oracle8.1.6 버전에 와서 그러한 제한이 해결되었다. 그 사용은 다음과 같다.

create table bookstore(

pk NUMBER PRIMARY KEY,

xml_text CLOB);

insert into bookstore values(111,'

<book>

<id>4</id>

<author>john LeCarre</author>

<title>the night manager</title>

</book>');

insert into bookstore values(112,'

<book>

<id>5</id>

<author>john grisham</author>

<title>the client</title>

</book>');

commit;

begin

ctx_ddl.create_section_group( 'xml_sections', 'xml_section_group');

ctx_ddl.add_zone_section ( 'xml_sections', 'titlesec', 'title');

ctx_ddl.add_zone_section ( 'xml_sections', 'authorsec', 'author');

ctx_ddl.create_preference ( 'my_basic_lexer', 'basic_lexer');

ctx_ddl.set_attributre ( 'my_basic_lexer', 'index_text','true');

ctx_ddl.set_attributre ( 'my_basic_lexer', 'index_themes','false');

end;

create index xml_index on bookstore(xml_text )

indextype is ctxsys.context

parameters ( 'lexer my_basic_lexer SECTION GROUP xml_sections');

select pk from bookstore

where contains(xml_text, 'LeCarre WITHIN authorsec')>0;

이 interMedia Text를 이용하면 XML 문서 전체 또는 일부를 저장할 때, 형태소 분석기를 이용하기 때문에 효과적인 검색을 할 수 있다. 단, 이 경우의 단점은 인덱스 크기가 매우 크다는 점과 자주 업데이트가 일어나는 경우, 인덱스를 재구성하는 시간이 길다는 점이다. 따라서, 신문 기사나 이력서와 같은 정적인 XML 문서를 저장하고 검색할 때 용이한 접근 방법이 될 수 있다.

XSQL Servlet

<그림5> XSQL Servlet의 구조

XSQL Servlet은 SQL, XML, XSLT를 이용하여 융통성 있는 정보 교환을 위해 만들어진 제품이다. 이는 SQL, XML, XSLT의 장점들을 조합하여 웹상의 HTTP 프로토콜을 통해 다음의 기능을 이용할 수 있게 한 것이다.

웹상의 임의의 디바이스로부터의 요구를 웹 환경을 통해 처리한다.

요구에 부합하는 적합한 논리적 비즈니스 자료에 대한 질의를 처리한다.

XML 포맷으로 질의 결과를 반환한다.

반환된 XML은 디바이스에 적절한 포맷 (XML, HTML 또는 텍스트 포맷) 등 으로 변환한다.

XSQL Servlet은 XSQL Page를 통해 오라클의 XDK (XML Devleoper’s Kit) 와 XSU (XML SQL Utility for java) 를 내부적으로 이용한다.

JSP를 사용해 보았다면, XSQL Page를 이해하기 쉬울 것이다.

리스트 7 ｃ emp.xsql

<?xml version="1.0"?>

<?xml-stylesheet type="text/xsl" href="emphtml.xsl"?>

<query connection="demo" id="7839">

SELECT *

FROM EMP

WHERE EMPNO = {@id}

</query>

|리스트 7|은 id를 입력 매개변수로 하여 SQL 질의어를 수행한 결과를 XML 포맷으로 받아서 XSLT를 통해 변환된 HTML 문을 최종적으로 사용자가 볼 수 있도록 해주는 XSQL Page이다.

이 XSQL Page는 다음과 같은 URL형태로 요구가 이루어진다.

--------------------------------------------------------------------------

http://<hostname>/<path>/emp.xsql?id=7499

--------------------------------------------------------------------------그리고, 요구가 수행되어진 결과는 |리스트 8|과 같다.

리스트 8 ｃ http://.../emp.xsql?id=7499의 수행 결과

<html>

< head>

<META http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Employee Info</title>

</head>

<body>

<table border="1" cellspacing="0">

<tr>

<th>Employee Name</th>

<th>Salary</th>

</tr>

<tr>

<td>ALLEN</td>

<td>1600</td>

</tr>

</table>

</body>

</html>

XSQL Servlet이 수행되는 과정은 <그림 5>를 보면서 자세히 이해해 보자. 먼저, 사용자는 휴대폰, PDA 또는 PC의 브라우저를 통해 URL 형태의 요구를 Java 웹 서버에 요구한다.

URL에 포함된 .xsql 파일은 XSQL Servlet에 의해 파싱되고, 파일내의 SQL 질의어는 XSU XML SQL Utility 에 의해서 JDBC를 통해 Oracle8i로 전달된다. Oracle8i는 질의어 결과를 XSU에게 반환하고 XSU는 결과를 XML 포맷으로 변환해서 서블릿에 전달한다. 이 때, XSLT가 .xsql 파일에 명시되어졌다면 XML 포맷으로 반환된 SQL 질의어와 나머지 부분의 XML이 XDK로 전달되어 XSLT에 명시된 변환 규칙에 따라 변환된 문서 포맷이 사용자에게 반환된다.

XML과 기타 전자 문서 표준에 지속적으로 관심 가져야

지금까지 XML의 개요와 오라클의 XML 지원 전략 그리고 오라클의 XML 지원 제품들에 대하여 설명하였다. 앞서 언급한 바와 같이 전자상거래와 같은 인터넷 기반의 애플리케이션에 있어 그 핵심적인 내용물이 되는 전자 문서의 표현과 저장은 XML에 의하여 지원될 것이다.

또한, 이 글에서 다루지는 않았지만, 전자 문서의 처리를 위한 표준으로는 XML뿐만 아니라 보다 많은 기능 지원을 위해 다양한 표준들 (예를 들면, XLink, XPointer, XPath, RDF, XML Schema 등) 이 계속적으로 정의되고 있다.

현재 XML이 가지는 중요성을 인식하고 해당 기술을 익히는 노력과 더불어 이러한 관련 표준에 대해서도 지속적으로 관심을 가지고 그 내용을 파악하는 노력이 상당히 중요할 것이다.

DOM API

DOM 트리 노드 인터페이스의 계층 구조

노드	계층구조 설명
Document	Document가 자식노드로 가질수 있는 태그는 문서의 최상의 태그를 말하며, XML 문서라면 반드시 하나가 존재해야 한다.
DocumentFragment	DocumentFragment는 DOM 트리의 실제 노드가 될 수는 없고 임시로 만들었다가 DOM 트리에 자식 노드로 붙게 되면 바로 다음 레벨의 노드들의 순차적으로 붙게된다.
DocuentType	DocumentType은 DOM 트리의 구성 노드가 아니라 Document의 속성값이다. 또한 자식 노드를 갖지 않으며 Entity와 Notation을 속성값으로 가지고 있다.
EntityReference	Entity 참조
Element	Element는 Attr을 속성값으로 갖는다
Attr	Attr은 태그의 속성값을 나타내는 것으로 Element의 속성값으로 실제 DOM 트리를 구성하지 않는다.
Entity	Entity는 DocumentType의 속성값으로 DOM 트리 구성에는 빠지지만 EntityReference에 의해 DOM트리에 삽입한다.
ProcessionInstruction, Comment, Text, CDATASection, Notation	자식 노드를 갖지 않는 노드들이며 Notation은 DocumentType의 속성값으로 DOM 트리에서 직접 참여하지 않는다.

이 그림에서 각각은 타입을 의미하며 가장 중요한 타입은 Node 타입이 되며 거의 모든 타입은 Node 타입을 상속받아 사용한다.

Node 타입은 가장 기본적인 타입으로써 부모 노드와 정해지지 않은 순서적 자식 노드를 가질 수 있으며, Elemenet 타입은 HTML이나 XML 문서의 엘리먼트(태그) 객체에 대한 내용을 가지며 Node 타입을 상속받는다.. 즉, Element 타입은 시작 태그와 종료 태그 사이에 있는 내용을 저장할 수 있으며, 이 Element 타입은 여러개의 Attribute를 가질 수 있다.

DocumentFragment 타입은 "lightweight" 또는 "minimal" Document 객체로서 문서의 일부분을 가지게 된다. Document 타입은 HTML이나 XML 문서의 루트 노트를 가진다.

또한 Attr은 엘리먼트의 속성, Text는 태그가 아닌 부분을 저장하게 되며, PI, Comment는 각각 Processing Instruction과 주석문에 대한 타입이 된다.

즉, 각 타입에 대하여 getNodeType, getParentNode, getChildNodes 등과 같은 메소드를 정의하고 있으며, Node 타입 뿐만 아니라 기타 타입에도 이와 같은 메소드가 존재한다.

Node

nodeName

노드의 이름을 나타냅니다.

appendChild(Child)

자식 리스트 끝에 덧붙여집니다.

insertBefore(Child, before)

기존의 자식노드인 before앞에 노드 child을 삽입하는 것이다.

replaceChild(Child, Replace)

Replace가 자식 리스트로부터 제거되고 Child이 그 자리에 추가된다.

removeChild(Child)

Child을 자식리스트로부터 제거됩니다.

cloneNode(deep)

노드의 복사본을 만드는데 사용된다. 만약 deep가 참이면, 그 밑의 모든 하위 트리의 완벽한 복사판이 리턴 됩니다.

Document

documentElement

문서 안에 가장 높은 레벨의 Element를 나타낸다.

createAttribute(name)

새로운 Attribute 노드를 생성하고 리턴한다.

createCDATASection(data)

data를 포함하는 새로운 CDATASection 노드를 생성하고 리턴한다.

createComment(data)

새로운 comment 노드를 생성하고 리턴 합니다.

createDocumentFragment()

새로운 createDocumentFragment 노드를 생성하고 리턴 합니다.

createElement(name)

Element 노드를 생성한다.

createEntityReference(name)

EntityReference노드를 생성하고 리턴 합니다.

createTextNode(String)

새로운 Text노드를 생성하고 리턴한다.

예제)

<html>

<script language="javascript" for="window" event="onload">

var newNode = xml.createElement("element2");

xml.documentElement.insertBefore(newNode, null);

confirm(xml.xml);

</script>

<xml id = "xml">

<rootElement>

<element1/>

</rootElement>

</xml>

</html>

예제2)

<html>

<script language="javascript" for="window" event="onload">

var nodeToDelete = xml.documentElement.childNodes.item(1);

xml.documentElement.removeChild(nodeToDelete);

confirm(xml.xml);

</script>

<xml id = "xml">

<rootElement>

<element1/>

<element2/>

</rootElement>

</xml>

</html>

예제3)

<html>

<script language="javascript" for="window" event="onload">

var nodeToMove = xml.documentElement.childNodes.item(1);

xml.documentElement.childNodes.item(0).appendChild(nodeToMove);

confirm(xml.xml);

</script>

<xml id = "xml">

<rootElement>

<element1/>

<element2/>

</rootElement>

</xml>

</html>

characterdata

appendData(data)

텍스트 스트링에 data를 추가한다.

insertData(int offset, String arg)

옵셋에 위치한 기존의 텍스트에 data를 입력하는 것

deleteData(offset, length)

옵셋에서부터 계산된 문자의 개수만큼 삭제.

replaceData(offset, lengtht, data)

옵셋에서 시작하는 텍스트 스트링부터 계산된 스트링과 옵셋 이후에 시작하는 기존의 스트링을 바꾼다

substringData(offset, length)

옵셋에서 시작하는 텍스트 스트링으로부터 계산된 문자의 개수를 리턴

Element

tagName

Element의 태그 이름을 나타냅니다.

setAttribute(name,value)

Attribute를 생성하고 값을 정의한다.

setAttribute(attr)

Attribute의 내용을 포함하는 스트링을 리턴 한다.

getAttributeNode(name)

Attribute 노드를 리턴한다.

removeAttribute(name)

Attribute 노드를 삭제한다.

setAttributeNode(newAttr)

Attribute노드를 추가한다.

예제)

<html>

<script language="javascript" for="window" event="onload">

var attrNode = xml.documentElement.getAttributeNode("myAttr");

xml.documentElement.removeAttributeNode(attrNode);

xml.documentElement.childNodes.item(0).setAttributeNode(attrNode);

confirm(xml.xml);

</script>

<xml id = "xml">

<rootElement myAttr="안녕하세요">

<myElem/>

</rootElement>

</xml>

</html>

예제)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<HTML><HEAD>

<META content="text/html; charset=ks_c_5601-1987" http-equiv=Content-Type>

<META content="MSHTML 5.00.2014.210" name=GENERATOR></HEAD>

<BODY onload=start()>

<SCRIPT language=javascript>

var ELEMENT_NODE = 1;

function start() {

var length = xml.documentElement.childNodes.length;

for (index = 0; index < length; index++) {

var childNode = xml.documentElement.childNodes.item(index);

if(childNode.nodeType == ELEMENT_NODE) {

confirm(childNode.nodeName);

}

}

}

</SCRIPT>

<xml id=xml>

<rootElement>

<element1/>

<element2/>

<element3/>

</rootElement>

</xml></BODY></HTML>