Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Atul.

Asked: January 10, 2002 - 12:05 pm UTC

Last updated: March 03, 2006 - 12:56 pm UTC

Version: 8i

Viewed 1000+ times

You Asked

Hi Tom,

I want to create a file (it's a spool from a table) in XML layout. What is the best way to do it. The only way I can think of is

select '<name>'||name||'<name/>, '<address>'||address||'<address/>
from T

Can you suggest anything better than this. Also Oracle provides an utility to create XML. What for is that?

Atul

and Tom said...

I asked Sean Dillon, our local XML guy to take a look at this. He says...

If you haven't already, you need to download and install the latest Oracle XML Developer's Kits (XDK's). What you are trying to do is relatively simple, and with the XDK, you can generate XML from SQL queries using PL/SQL, Java, C or C++. The following command on the command line generates an XML document containing the first 4 rows of the SCOTT.EMP table:

$ java OracleXML getXML -user "scott/tiger" "select * from emp where rownum < 5" > emp.xml

$ cat emp.xml
<?xml version = '1.0'?>
<ROWSET>
<ROW num="1">
<EMPNO>7369</EMPNO>
<ENAME>SMITH</ENAME>
<JOB>CLERK</JOB>
<MGR>7902</MGR>
<HIREDATE>12/17/1980 0:0:0</HIREDATE>
<SAL>800</SAL>
<DEPTNO>20</DEPTNO>
</ROW>
<ROW num="2">
<EMPNO>7499</EMPNO>
<ENAME>ALLEN</ENAME>
<JOB>SALESMAN</JOB>
<MGR>7698</MGR>
<HIREDATE>2/20/1981 0:0:0</HIREDATE>
<SAL>1600</SAL>
<COMM>300</COMM>
<DEPTNO>30</DEPTNO>
</ROW>
<ROW num="3">
<EMPNO>7521</EMPNO>
<ENAME>WARD</ENAME>
<JOB>SALESMAN</JOB>
<MGR>7698</MGR>
<HIREDATE>2/22/1981 0:0:0</HIREDATE>
<SAL>1250</SAL>
<COMM>500</COMM>
<DEPTNO>30</DEPTNO>
</ROW>
<ROW num="4">
<EMPNO>7566</EMPNO>
<ENAME>JONES</ENAME>
<JOB>MANAGER</JOB>
<MGR>7839</MGR>
<HIREDATE>4/2/1981 0:0:0</HIREDATE>
<SAL>2975</SAL>
<DEPTNO>20</DEPTNO>
</ROW>
</ROWSET>

There are a variety of options with this Java class (OracleXML) as well...

$ java OracleXML
OracleXML-Error:wrong argument list
Call with

OracleXML getXML
[-user "username/password"] -- the user name and password
[-conn "JDBC_connect_string"] -- JDBC connect string
[-withDTD | -withSchema] -- generate the DTD/Schema
[-rowsetTag <rowsetTag>] -- document tag name
[-rowTag <rowTag>] -- row element tag name
[-rowIdAttr <attrName>] -- row-id attribute name
[-rowIdColumn <column_name>] -- db-column to use for the row id
[-collectionIdAttr <attrName>] -- collection element-id attribute
[-useTypeForCollElemTag] -- use type name for coll-elem tag
[-useNullAttrId] -- use a null attribute
[-styleSheet <URI>] -- stylesheet processing instruction header
[-styleSheetType <type>] -- stylesheet header type (e.g.text/xsl)
[-setXSLT <URI>] -- XSLT to apply to XML doc
[-setXSLTRef <URI>] -- XSLT external entity reference
[-useLowerCase| -useUpperCase] -- the case of the tag names
[-withEscaping] -- if necessary do SQL-XML name escaping
[-errorTag <errorTagName>] -- error tag name
[-raiseException] -- raise exceptions for errors
[-raiseNoRowsException] -- raise exception if no returned
[-maxRows <maxRows>] -- maximum rows in output
[-skipRows <skipRows>] -- rows to skip in output
[-encoding <encoding_name>] -- encoding to be used
[-dateFormat <date format>] -- date format to be used
(<query>| -fileName <sqlfile>) -- SQL query | file containing the query

-- OR --

OracleXML putXML
[-user "username/password"] -- the user name and password
[-conn "JDBC_connect_string"] -- JDBC connect string
[-batchSize <size>] -- number of inserts executed at a time
[-commitBatch <size>] -- number of inserts commited at a time
[-rowTag <rowTagName>] -- the name for row elements
[-dateFormat <format>] -- the format of date elements
[-withEscaping] -- if necessary do SQL-XML name escaping
[-ignoreCase] -- ignore the case of the tag namess
[-setXSLT <URI>] -- XSLT to apply to XML doc
[-setXSLTRef <URI>] -- external entity reference for XSLT doc
[-fileName fileName | -- the XML document file name or
-URL url | - URL or
-xmlDoc <XMLDocumentString>] - XML string
<tableName> -- the table name to put into

This is Java, however, and it might not fit your needs at all. Alternatively, you could use the PL/SQL equivalent functionality to generate XML from a SQL query using the package DBMS_XMLQUERY:

SQL> var my_xml clob
SQL> set autoprint on
SQL> declare
2 -- l_clob clob;
3 l_ctx dbms_xmlgen.ctxHandle;
4 l_sql varchar2(400);
5 begin
6 l_sql := 'select *
7 from emp
8 where rownum < 5';
9
10 l_ctx := dbms_xmlgen.newContext(l_sql);
11 :my_xml := dbms_xmlgen.getXml(l_ctx); -- or you could assign it to l_clob
12 end;
13 /

PL/SQL procedure successfully completed.

MY_XML
----------------------------------------------
<?xml version="1.0"?>
<ROWSET>
<ROW>
<EMPNO>7369</EMPNO>
<ENAME>SMITH</ENAME>
<JOB>CLERK</JOB>
<MGR>7902</MGR>
<HIREDATE>17-DEC-80</HIREDATE>
<SAL>800</SAL>
<DEPTNO>20</DEPTNO>
</ROW>
<ROW>
<EMPNO>7499</EMPNO>
<ENAME>ALLEN</ENAME>
<JOB>SALESMAN</JOB>
<MGR>7698</MGR>
<HIREDATE>20-FEB-81</HIREDATE>
<SAL>1600</SAL>
<COMM>300</COMM>
<DEPTNO>30</DEPTNO>
</ROW>
<ROW>
<EMPNO>7521</EMPNO>
<ENAME>WARD</ENAME>
<JOB>SALESMAN</JOB>
<MGR>7698</MGR>
<HIREDATE>22-FEB-81</HIREDATE>
<SAL>1250</SAL>
<COMM>500</COMM>
<DEPTNO>30</DEPTNO>
</ROW>
<ROW>
<EMPNO>7566</EMPNO>
<ENAME>JONES</ENAME>
<JOB>MANAGER</JOB>
<MGR>7839</MGR>
<HIREDATE>02-APR-81</HIREDATE>
<SAL>2975</SAL>
<DEPTNO>20</DEPTNO>
</ROW>
</ROWSET>

SQL> set autoprint off

The DBMS_XMLQUERY package has a GETXML function that takes in a SQL query and returns a CLOB without having to create a context and go into the overhead, but I recommend using the context handle in the PL/SQL block; it gives you an enormous amount of functionality (most of which is absolutely necessary in a production application) such as binding variables to your query, generating a DTD or Schema for your XML, modifying the names of the ROWSET and ROW elements, limiting the number of rows returned, etc.

You can find the latest copies of the XML Developer's Kits on the Oracle Technology Network's XML pages...

</code> http://technet.oracle.com/tech/xml/content.html <code>

Hope that helps!

Rating

  (51 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Can we do for HTML also?

AB, January 11, 2002 - 7:34 am UTC

Is there an HTML equivalent? I have no Oracle Web tools and won't be able to have either.

I currently have my intranet set up to monitor db activity. I have a UNIX box with a webserver daemon and a PC with a browser. Currently I call an HTML script on the UNIX box which calls a shell script. This shell script executes a package.procedure. The procedure "DBMS_OUTPUTs" a combination of html tags and the resultset from cursors. The shell script pipes this back to the browser. As dynamic as I can get with my set up, so an "html-generator" like the XML one above would be great.



Tom Kyte
January 11, 2002 - 10:59 am UTC

AB,

Oracle8.1.7 comes with an Apache web listener and MOD_PLSQL, an Apache add-on that lets you write PL/SQL procedures to produce web pages. If you have access to an 8.1.7 database, the code you need to install and configure the PL/SQL Web Toolkit is located in the $ORACLE_HOME/Apache/modplsql directory.

The PL/SQL Web Toolkit let's you spool data to an HTML buffer instead of the DBMS_OUTPUT buffer. The toolkit contains packages (with procedures and functions) for creating html. Using this approach, you could do something like this:

connect scott/tiger

create or replace package xml_reports as
procedure employees;
procedure departments;
end xml_reports;
/

create or replace package body xml_reports as

procedure to_html(p_xml in out nocopy clob) is
l_xml varchar2(30000);
l_line varchar2(2000);
l_amt pls_integer := 30000;
l_idx pls_integer := 1;
begin
for i in 1 .. ceil(dbms_lob.getlength(p_xml)/l_amt) loop
l_xml := dbms_lob.substr(p_xml, l_amt, l_idx);
loop
exit when l_xml is null;
l_line := substr(l_xml, 1, instr(l_xml, chr(10))-1);
-- THIS IS THE SQLPLUS OUTPUT STYLE
--dbms_output.put_line('|' || l_line);
-- THIS IS THE HTML OUTPUT STYLE
htp.put_line(l_line);
l_xml := substr(l_xml, instr(l_xml, chr(10))+1);
end loop;
end loop;
end to_html;

procedure employees
is
l_clob clob;
l_ctx dbms_xmlgen.ctxHandle;
l_sql varchar2( 400 );
begin
l_sql := 'select *
from emp';
l_ctx := dbms_xmlgen.newContext( l_sql );
l_clob := dbms_xmlgen.getXml( l_ctx );
to_html( l_clob );
end employees;

procedure departments
is
l_clob clob;
l_ctx dbms_xmlgen.ctxHandle;
l_sql varchar2( 400 );
begin
l_sql := 'select *
from dept';
l_ctx := dbms_xmlgen.newContext( l_sql );
l_clob := dbms_xmlgen.getXml( l_ctx );
to_html( l_clob );
end departments;
end xml_reports;
/
show error

With this package procedure, I could put this in my browser:

</code> http://servername:port/pls/dbconfig/xml_reports.employees

...and get the following results in my browser:

<?xml version="1.0"?>
<ROWSET>
 <ROW>
  <EMPNO>7369</EMPNO>
  <ENAME>SMITH</ENAME>
  <JOB>CLERK</JOB>
  <MGR>7902</MGR>
  <HIREDATE>17-DEC-80</HIREDATE>
  <SAL>800</SAL>
  <DEPTNO>20</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7499</EMPNO>
  <ENAME>ALLEN</ENAME>
  <JOB>SALESMAN</JOB>
  <MGR>7698</MGR>
  <HIREDATE>20-FEB-81</HIREDATE>
  <SAL>1600</SAL>
  <COMM>300</COMM>
  <DEPTNO>30</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7521</EMPNO>
  <ENAME>WARD</ENAME>
  <JOB>SALESMAN</JOB>
  <MGR>7698</MGR>
  <HIREDATE>22-FEB-81</HIREDATE>
  <SAL>1250</SAL>
  <COMM>500</COMM>
  <DEPTNO>30</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7566</EMPNO>
  <ENAME>JONES</ENAME>
  <JOB>MANAGER</JOB>
  <MGR>7839</MGR>
  <HIREDATE>02-APR-81</HIREDATE>
  <SAL>2975</SAL>
  <DEPTNO>20</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7654</EMPNO>
  <ENAME>MARTIN</ENAME>
  <JOB>SALESMAN</JOB>
  <MGR>7698</MGR>
  <HIREDATE>28-SEP-81</HIREDATE>
  <SAL>1250</SAL>
  <COMM>1400</COMM>
  <DEPTNO>30</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7698</EMPNO>
  <ENAME>BLAKE</ENAME>
  <JOB>MANAGER</JOB>
  <MGR>7839</MGR>
  <HIREDATE>01-MAY-81</HIREDATE>
  <SAL>2850</SAL>
  <DEPTNO>30</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7782</EMPNO>
  <ENAME>CLARK</ENAME>
  <JOB>MANAGER</JOB>
  <MGR>7839</MGR>
  <HIREDATE>09-JUN-81</HIREDATE>
  <SAL>2450</SAL>
  <DEPTNO>10</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7788</EMPNO>
  <ENAME>SCOTT</ENAME>
  <JOB>ANALYST</JOB>
  <MGR>7566</MGR>
  <HIREDATE>19-APR-87</HIREDATE>
  <SAL>3000</SAL>
  <DEPTNO>20</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7839</EMPNO>
  <ENAME>KING</ENAME>
  <JOB>PRESIDENT</JOB>
  <HIREDATE>17-NOV-81</HIREDATE>
  <SAL>5000</SAL>
  <DEPTNO>10</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7844</EMPNO>
  <ENAME>TURNER</ENAME>
  <JOB>SALESMAN</JOB>
  <MGR>7698</MGR>
  <HIREDATE>08-SEP-81</HIREDATE>
  <SAL>1500</SAL>
  <COMM>0</COMM>
  <DEPTNO>30</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7876</EMPNO>
  <ENAME>ADAMS</ENAME>
  <JOB>CLERK</JOB>
  <MGR>7788</MGR>
  <HIREDATE>23-MAY-87</HIREDATE>
  <SAL>1100</SAL>
  <DEPTNO>20</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7900</EMPNO>
  <ENAME>JAMES</ENAME>
  <JOB>CLERK</JOB>
  <MGR>7698</MGR>
  <HIREDATE>03-DEC-81</HIREDATE>
  <SAL>950</SAL>
  <DEPTNO>30</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7902</EMPNO>
  <ENAME>FORD</ENAME>
  <JOB>ANALYST</JOB>
  <MGR>7566</MGR>
  <HIREDATE>03-DEC-81</HIREDATE>
  <SAL>3000</SAL>
  <DEPTNO>20</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>7934</EMPNO>
  <ENAME>MILLER</ENAME>
  <JOB>CLERK</JOB>
  <MGR>7782</MGR>
  <HIREDATE>23-JAN-82</HIREDATE>
  <SAL>1300</SAL>
  <DEPTNO>10</DEPTNO>
 </ROW>
</ROWSET>

For more information on the packages that make up the package, look here:

http://db.lib.vt.edu/ows-adoc/psqlwtlk.htm <code>

I hope that helps!

-SEAN- ;-)

PL/SQL to HTML

AB, January 11, 2002 - 11:10 am UTC

Tom,

Thankyou very much. This was exactly what I was looking for. I just need to work out how to format the output into grids etc now.

BTW, you are THE Oracle resource on the www. If I had as many people praising me as they do you, I'd have the ego the size of a rock star !!!

While I'm at it, your book is AMAZING also. Possibly the best actually. We don't need continual syntax manuals, we need APPROACH manuals, and you sure are changing the way I approach my applications.

Thanks again.
AB

XMLGEN and Cursors

Edgar, January 15, 2002 - 6:20 am UTC

Hello Tom and Sean!

This is all great, that we can use dbms_xmlgen to generate xml directrly from PL/SQL, but as I can see in manuals dbms_xmlgen.newContext() accepts parameter as simple static sql, from this site we all know that static sql is evil and that we have to use binding capabilities. Is there a way to generate xml from select passing as argument cursor or something like this?

Tom Kyte
January 15, 2002 - 9:34 am UTC

Hi Edgar Sean here...

Yes good point, I prolly should have included the bind variables as a part of the example... There are a couple of ways to handle this. Luckily, in DBMS_XMLQUERY we have the SETBINDVALUE procedure, so you could code it this way:

SQL> create or replace function get_emps_in_dept( p_deptno in number )
  2    return clob
  3  is
  4    l_ctx dbms_xmlquery.ctxType;
  5    l_sql varchar2(100);
  6    l_xml clob;
  7  begin
  8    l_sql := 'select * from emp where deptno = :deptno';
  9    dbms_lob.createtemporary( l_xml, true, dbms_lob.session );
 10    l_ctx := dbms_xmlquery.newContext( l_sql );
 11
 12    dbms_xmlquery.setbindvalue( l_ctx, 'deptno', p_deptno );
 13
 14    dbms_xmlquery.setRaiseNoRowsException( l_ctx,false );
 15
 16    -- get the xml fm the context
 17    l_xml := dbms_xmlquery.getXML( l_ctx );
 18
 19    dbms_xmlquery.closeContext(l_ctx);
 20    return l_xml;
 21  exception
 22    when others then
 23      dbms_xmlquery.closeContext(l_ctx);
 24      raise;
 25  end get_emps_in_dept;
 26  /
Function created.

Then, if we test it, we can look in the v$sqlarea for matches:

SQL> declare
  2    l_clob clob;
  3  begin
  4    l_clob := get_emps_in_dept( 10 );
  5  end;
  6  /

PL/SQL procedure successfully completed.

SQL> select count(*), executions
  2    from v$sqlarea
  3   where sql_text like 'select * from emp where deptno =%'
  4   group by executions;

  COUNT(*) EXECUTIONS
---------- ----------
         1          1

If we run it a whole bunch of times, we get the same response:

SQL> declare
  2    l_clob clob;
  3  begin
  4    for i in 1 .. 100 loop
  5      l_clob := get_emps_in_dept( i );
  6    end loop;
  7  end;
  8  /

PL/SQL procedure successfully completed.

SQL>
SQL> select count(*), executions
  2    from v$sqlarea
  3   where sql_text like 'select * from emp where deptno =%'
  4   group by executions;

  COUNT(*) EXECUTIONS
---------- ----------
         1        101
In the case where an API doesn't have the ability to set bind variables, there are a couple of approaches you can use. Cursor sharing is the way to tell the database to do this for us:

execute immediate 'alter session set cursor_sharing = force';
then call the API
execute immediate 'alter session set cursor_sharing = exact';

will do it in 8.1.6 and up (an autobinder feature -- good for wierd cases like this)

As well, you can use the technique outlined on:

http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:1288401763279

using an application context.  You would use dbms_session.set_context to "bind" instead of dbms_sql.bind_variable.
 

Using XML

reader, April 26, 2003 - 8:05 am UTC

SQL>desc employees ;
 Name                                                  Null?    Type
 ----------------------------------------------------- -----
 ID                                                             NUMBER
 FNAME                                                          VARCHAR2(100)
 LNAME                                                          VARCHAR2(100)

SQL>SELECT XMLELEMENT ( "Emp", XMLATTRIBUTES (e.id,e.fname ||' ' || e.lname AS "name")) AS "result" FROM employees e;
/

result()
============================================================
XMLTYPE()
XMLTYPE()
XMLTYPE()

what is wrong in this, i am not getting the expected output. please clarify.

Thanks 

Tom Kyte
April 26, 2003 - 8:50 am UTC

works for me --

scott@ORA920LAP> sELECT XMLELEMENT ( "Emp", XMLATTRIBUTES (e.empno,e.ename ||' ' || e.job AS
2 "name")) AS "result" FROM emp e;

result
-----------------------------------------------------------------------------------------------------------------------------------
<Emp EMPNO="7369" name="SMITH CLERK"></Emp>
<Emp EMPNO="7499" name="ALLEN SALESMAN"></Emp>
<Emp EMPNO="7521" name="WARD SALESMAN"></Emp>
<Emp EMPNO="7566" name="JONES MANAGER"></Emp>
<Emp EMPNO="7654" name="MARTIN SALESMAN"></Emp>
<Emp EMPNO="7698" name="BLAKE MANAGER"></Emp>
<Emp EMPNO="7782" name="CLARK MANAGER"></Emp>
<Emp EMPNO="7788" name="SCOTT ANALYST"></Emp>
<Emp EMPNO="7839" name="KING PRESIDENT"></Emp>
<Emp EMPNO="7844" name="TURNER SALESMAN"></Emp>
<Emp EMPNO="7876" name="ADAMS CLERK"></Emp>
<Emp EMPNO="7900" name="JAMES CLERK"></Emp>
<Emp EMPNO="7902" name="FORD ANALYST"></Emp>
<Emp EMPNO="7934" name="MILLER CLERK"></Emp>

14 rows selected.


Using XML

reader, April 26, 2003 - 9:04 am UTC

SQL>select xmlelement("Employees",
  2               xmlagg(
  3                 xmlelement(
  4                   "Employee",
  5                   xmlforest(empno, ename, sal)))) as "result"
  6        from emp
  7  ;

result()
============================================================
XMLTYPE()

I am stuck here,.. not able to proceed. can it be because of any settings that needs to be changed. remember it was working earlier..
 

Tom Kyte
April 26, 2003 - 11:50 am UTC

it works for me.

I do not remember that it was working earlier -- i've no clue who you are.

You are not cutting and pasting from sqlplus -- result() wouldn't appear there, it would be result and we use ---- not ======= so I can only guess you are using toad or something else and they are punting when it comes to displaying an object type.




A reader, April 26, 2003 - 12:14 pm UTC

Tom,

trust me - It didnt work...

i restarted and put the same query - it worked.

i have been out for dinner, after 45 minutes, i read your reply, thought i would say its working now - but again the query failed.

the sqlplus which was working - i still have it opened. opened a new session, its failing now. !

SQL>       select xmlelement("Employees",
  2                         xmlagg(
  3                           xmlelement(
  4                             "Employee",
  5                             xmlforest(empno, ename, sal)))) as "result"
  6                  from emp
  7            ;

result()
============================================================
XMLTYPE()

the other window which is working :

SQL>        select xmlelement("Employees",
  2                         xmlagg(
  3                           xmlelement(
  4                             "Employee",
  5                             xmlforest(empno, ename, sal)))) as "result"
  6                  from emp
  7            ;

result
--------------------------------------------------------------------------------
<Employees>
  <Employee>
    <EMPNO>7369</EMPNO>
    <ENAME>SMITH</ENAME>
    <SAL>800</SAL>
  </Employee>
  <Employee>
    <EMPNO>7499</EMPNO>
    <ENAME>ALLEN</ENAME>
    <SAL>1600</SAL>
  </Employee>

result
--------------------------------------------------------------------------------
  <Employee>
    <EMPNO>7521</EMPNO>

.... continues

    <SAL>1300</SAL>
  </Employee>
</Employees>


may be i need to restart and test it again. 

I would never waste your time, that you dedicate for us. i daily visit your site and learn a lot.

Thanks
 

Shailesh, May 21, 2003 - 7:21 am UTC

I created package xml_reports and two procedures as given
in the example. However when i place the link
http://172.17.19.140:80/xml_reports.employees
I get error
Page cannot be found.
Also there is a message given
HTTP-404 - File not found.
My apache server is running on 
SQL> host
$ ps -ef|grep apache
     www  3363  1914  0  Apr 11  ?         0:00 /opt/apache/bin/httpd
     www  1926  1914  0  Apr 10  ?         0:00 /opt/apache/bin/httpd
    root  1914     1  0  Apr 10  ?         2:15 /opt/apache/bin/httpd
     www  1927  1914  0  Apr 10  ?         0:00 /opt/apache/bin/httpd
     www  1928  1914  0  Apr 10  ?         0:00 /opt/apache/bin/httpd
     www  1929  1914  0  Apr 10  ?         0:00 /opt/apache/bin/httpd
     www  1930  1914  0  Apr 10  ?         0:00 /opt/apache/bin/httpd
     www 11484  1914  0  Apr 24  ?         0:00 /opt/apache/bin/httpd
     www 17274  1914  0  Apr 17  ?         0:00 /opt/apache/bin/httpd
     www 20836  1914  0  Apr 30  ?         0:00 /opt/apache/bin/httpd
oracle9i 17638 16418  0 16:37:13 pts/tk    0:00 grep apache

The OS is HP-UX 11i and db version is 9.0.1.4.
please help

Regards
Shailesh 

How can we sort the extract() results?

A Reader, July 16, 2003 - 4:13 pm UTC

We have a query like the following:

select * from (select extract(xmldetail, '/XMLDetail/Detail/text()')
from t_with_xmltype) order by 1
*
We get the following error:
ERROR at line 1:
ORA-22950: cannot ORDER objects without MAP or ORDER method

How can we sort the result set returned from an XML query?
Thank you very much for your help.


Tom Kyte
July 16, 2003 - 4:21 pm UTC

well, that is an "object", an XML document, being returned.


if the detail is a scalar, perhaps you meant to use extractvalue?

Generate XML from Type as Table of Object

JK, July 25, 2003 - 6:27 pm UTC

Hi Tom,

Can you please suggest what is wrong in this?
CREATE OR REPLACE TYPE datastack AS OBJECT (
ATTRIB_NAME VARCHAR2(40), --This should be the Tag
ATTRIB_VALUE VARCHAR2(40)); -- This is the value
Inside my Procedure I have
TYPE datacontext is TABLE OF datastack;
dump_data_stack datacontext := datacontext();

The dump_data_stack is updated with data. This is something similar to a call_stack but will be populated with data from within the procedures. If there is an exception in the procedure, this data_stack will be dumped into error_log table as a XML.

Here comes my problem.
l_ctx := dbms_xmlquery.newContext(
'select * from THE ( select cast( dump_data_stack as datacontext )from dual ) a');

l_xml_payload := dbms_xmlquery.getXml(l_ctx);

throws
"XML IS: ***<?xml version = '1.0'?>
<ERROR>oracle.xml.sql.OracleXMLSQLException:
ORA-00902: invalid datatype" this error.

I couldnt resolve it. So, i tried this:
FOR stack_index IN 1 .. top_of_data_stack
LOOP
l_attrib_name := '"' || dump_data_stack (stack_index).attrib_name || '"';
SELECT XMLElement (l_attrib_name,
dump_data_stack (stack_index).attrib_value )
INTO l_xml
FROM DUAL;
l_xml_payload := l_xml.getClobVal();
l_call_stack_text := l_call_stack_text || l_xml_payload;

This prints as
"<L_ATTRIB_NAME>234567899</L_ATTRIB_NAME><L_ATTRIB_NAME>Mary M Beth</L_ATTRIB_NAME><L_ATTRIB_NAME>Margin Account</L_ATTRIB_NAME> ..."

I expected/require it to be something like this:
"<SSN>234567899</SSN><NAME>Mary M Beth</NAME> <ACCOUNT>Margin Account</ACCOUNT> ..."

Can you please suggest some option? Also is there a better way to dump data log to the table? I update the stack through the course of the procedure and then plan to dump it.

Thanks & Regards
JK

Tom Kyte
July 25, 2003 - 8:41 pm UTC

datacontext must be defined at the sql level, it is not visible to SQL when it is defined in that procedure.

How to separate the xml results

Yong Wu, September 03, 2003 - 8:14 pm UTC

I ran the following query and expect results like

Administrative
Business

But the results are always concatenated. How to fix the problem?

Thanks,

SQL> l
  1  begin
  2   for c in (select x.content.extract('/School//Category/@CodeName').getStringVal()
  3  Category
  4  from xml_data x) loop
  5  dbms_output.put_line(c.category);
  6  end loop;
  7* end ;
SQL> /
AdministrativeBusiness

 

Tom Kyte
September 04, 2003 - 8:49 am UTC

hmm, no table xml_data in my database

no xml to peek at.

sort of hard to say anything without a full, yet concise and simple, test case (which I find I frequently find my own mistakes in when putting it together)

Here is test data

Yong Wu, September 04, 2003 - 3:19 pm UTC

Tom,

Here is the test data. Thanks for your help.

create table xml_data 
  (id number,
   name varchar2(60),
   status varchar2(20),
   created_date date default sysdate,
   content xmltype);

insert into xml_data values(1,'EDU Program','New',sysdate,
'<School codekey="3028" Name="Vatterott College">
     <QualificationMajor CodeName=”Undergraduate” DisplayName="Undergraduate" Description=”Undergraduate”>
         <QualificationMinor CodeName=”Associate” DisplayName="Associate" Description="Associate">
         <QualificationMinor CodeName=”Bachelor” DisplayName="Bachelor" Description=” Bachelor">
     </Qualification>
     <QualificationMajor CodeName="Graduate"  DisplayName="Graduate" Description=”Undergraduate”>
         <QualificationMinor CodeName="Bachelor" DisplayName="Bachelor" Description="Bachelor">
         <QualificationMinor CodeName="Doctorate" DisplayName="Doctorate" Description="Doctorate">
     </Qualification>

     <Campus codekey="302072" Name="Cleveland">
       <Category CodeName="Administrative" DisplayName="Administrative">
         <SubCategory CodeName="BUSINESSADMINISTRATIVEASSISTANT(1OF2)" DisplayName="Business Administrative Assistant">
           <Program CodeName="210AASD" DisplayName="Administrative Applications Specialist" AlternativeName="210AASD" />
       <Program CodeName="210AOSA" DisplayName="Administrative Office Specialist" AlternativeName="210AOSA" />
       <Program CodeName="210COAD" DisplayName="Computer Office Assistant" AlternativeName="210COAD" />
     </SubCategory>
       </Category>
       <Category CodeName="Business" DisplayName="Business">
     <SubCategory CodeName="ACCOUNTING(1OF2)" DisplayName="Accounting">
           <Program CodeName="210ACCA" DisplayName="Accounting " AlternativeName="210ACCA" />
         </SubCategory>
       </Category>
     </Campus>
</School>');

SQL> l
  1  begin
  2   for c in (select x.content.extract('/School//Category/@CodeName').getStringVal()
  3  Category
  4  from xml_data x) loop
  5  dbms_output.put_line(c.category);
  6  end loop;
  7* end ;
SQL> /
AdministrativeBusiness
 

Tom Kyte
September 05, 2003 - 3:14 pm UTC

sorry -- this example is so far away from even slightly working.....

you have an xmltype, you are inserting char

you have a <QualificationMajor> tag that is ended with /Qualification

you have QualificationMinor tags that are not even ended....

please, make sure the stuff at least *runs*

Yong Wu, September 05, 2003 - 3:39 pm UTC

I am realy sorry for posting wrong sql. Here is the query.

insert into xml_data values(1,'EDU Program','New',sysdate,
xmltype('<School codekey="3028" Name="Vatterott College">
     <QualificationMajor CodeName="Undergraduate" DisplayName="Undergraduate" Description="Undergraduate">
         <QualificationMinor CodeName="Associate" DisplayName="Associate" Description="Associate" />
         <QualificationMinor CodeName="Bachelor" DisplayName="Bachelor" Description="Bachelor" />
     </QualificationMajor>
     <QualificationMajor CodeName="Graduate"  DisplayName="Graduate" Description="Undergraduate">
         <QualificationMinor CodeName="Bachelor" DisplayName="Bachelor" Description="Bachelor" />
         <QualificationMinor CodeName="Doctorate" DisplayName="Doctorate" Description="Doctorate" />
     </QualificationMajor>
     <Campus codekey="302072" Name="Cleveland">
       <Category CodeName="Administrative" DisplayName="Administrative">
         <SubCategory CodeName="BUSINESSADMINISTRATIVEASSISTANT(1OF2)" DisplayName="Business Administrative Assistant">
           <Program CodeName="210AASD" DisplayName="Administrative Applications Specialist" AlternativeName="210AASD" />
       <Program CodeName="210AOSA" DisplayName="Administrative Office Specialist" AlternativeName="210AOSA" />
       <Program CodeName="210COAD" DisplayName="Computer Office Assistant" AlternativeName="210COAD" />
     </SubCategory>
       </Category>
       <Category CodeName="Business" DisplayName="Business">
     <SubCategory CodeName="ACCOUNTING(1OF2)" DisplayName="Accounting">
           <Program CodeName="210ACCA" DisplayName="Accounting " AlternativeName="210ACCA" />
         </SubCategory>
       </Category>
     </Campus>
</School>'));

SQL> select x.content.extract('/School//Category/@CodeName').getStringVal() 
  2  Category
from xml_data x;
  3  
CATEGORY
--------------------------------------------------------------------------------
AdministrativeBusiness

SQL> select x.content.extract('/School//SubCategory/@CodeName').getStringVal() 
  2  SubCategory
  3  from xml_data x;

SUBCATEGORY
--------------------------------------------------------------------------------
BUSINESSADMINISTRATIVEASSISTANT(1OF2)ACCOUNTING(1OF2)

Thanks for your help 

Yong Wu, September 09, 2003 - 1:04 pm UTC

I tried another query it returns the same 

SQL> select extract(content,'/School//SubCategory/@CodeName').getStringVal() from xml_data;

EXTRACT(CONTENT,'/SCHOOL//SUBCATEGORY/@CODENAME').GETSTRINGVAL()
--------------------------------------------------------------------------------
BUSINESSADMINISTRATIVEASSISTANT(1OF2)ACCOUNTING(1OF2)

I would like to know how to spit the results like

BUSINESSADMINISTRATIVEASSISTANT(1OF2)
ACCOUNTING(1OF2)

Thanks, 

Tom Kyte
September 10, 2003 - 12:29 pm UTC

Hi Yong, Sean Dillon here.  You want to use an operator in Oracle9iR2 called XMLSequence.  You can read all about XMLSequence in the documentation (Oracle XML DB Developer's Handbook).  XMLSequence turns an extract result into a set of XMLType documents instead of a single XMLType result set.  You then use the TABLE function to turn that set of XMLType documents into a source from which you can query:

SQL> select extractvalue(value(d), '/SubCategory/@CodeName')
  2    from xml_data x,
  3         table( xmlsequence( extract(x.content, '/School//SubCategory') ) ) d
  4  /

EXTRACTVALUE(VALUE(D),'/SUBCATEGORY/@CODENAME')
--------------------------------------------------------------------------------
BUSINESSADMINISTRATIVEASSISTANT(1OF2)
ACCOUNTING(1OF2)

Hope that helps!

Sean Dillon - Principal Technologist, Oracle Corporation 
Author "Beginning Oracle Programming" www.amazon.com/exec/obidos/ASIN/186100690X
 

Yong Wu, September 10, 2003 - 1:54 pm UTC

Sean,

It works.
I follow Oracle on-line document Oracle9i XML Database Developer's Guide and didn't reach far enough to find a good example.

Great! It helpe me a lot.

Thanks,

Error in creating a xml schema

Yong Wu, September 10, 2003 - 2:14 pm UTC

Sean,

I tried to create/register a xml schema and got an error.
Would you please let me know what is wrong with this error or some setup problem?

create table po_tab(
id number,
po sys.XMLType
)
xmltype column po
XMLSCHEMA "</code> http://www.oracle.com/PO.xsd" <code>
element "PurchaseOrder";
create table po_tab(
*
ERROR at line 1:
ORA-01001: invalid cursor
ORA-21700: object does not exist or is marked for delete

Thanks

Tom Kyte
September 10, 2003 - 8:13 pm UTC

thats not a valid url

---

Hi Sean here... in the SQL reference, look up the create table statement. Under the XML Schema explanation, it states if you specify an XMLSCHEMA for your column storage, you must have already registered the XML Schema with the database. Page 15-42:

"If you do specify an XMLSchema URL, you must already have registered the XMLSchema using the DBMS_XMLSCHEMA package."

You can lookup DBMS_XMLSCHEMA in the "Supplied PL/SQL Packages and Types Reference." Basically the REGISTER_SCHEMA procedure tells Oracle you will be storing XML according to a particular schema, and creates the underlying storage mechanism for that schema. For more information about this, you can read Chapter 5, Structured Mapping of XMLType of the "XML Database Developer's Guide". Hope that helps!

dynamic SQL with XML

vll, January 27, 2004 - 12:53 pm UTC

Hi, Tom!
Am I doing something wrong?

With direct SQL:
select xmlelement("RESULTS") into sc_xml.result from dual;
everything is fine (sc_xml.result is a package variable). When I'm trying to do it with dynamic SQL - i'm getting error:
strSQL := 'select xmlelement("RESULTS") into sc_xml.result from dual';
execute immediate strSQL;

error is:ORA-00905: missing keyword.

Is there any way to build XML queries dynamically?
Thank you very-very much!!!

Tom Kyte
January 27, 2004 - 1:17 pm UTC

INTO :variable

is a plsql thing. INTO is not sql.

strSQL := 'select xmlelement("RESULTS") from dual';
execute immediate strSQL into sc_xml.result;




Using XMLSequence

Raghu, February 19, 2004 - 9:35 am UTC

I have registered a xml schema in the database.
then i created a table based on the xml schema.
then i inserted the xml data into the table using the file from XML repository.
Here are the scripts.

CREATE TABLE TabL_FileContent
(
id NUMBER,
SequenceData XMLType,
FileContent BLOB
)
XMLTYPE COLUMN SequenceData
STORE AS OBJECT RELATIONAL
XMLSCHEMA "</code> http://www.w3.org/2001/XMLSchema/XMLAblDaten.xsd"
ELEMENT "MEPSequenceData";


INSERT INTO TabL_FileContent VALUES
( 1
  ,XMLTYPE(XDBURITYPE('/public/labor/ftp_path/xmlabldaten.xml').GetClob())
  , EMPTY_BLOB()
)
/

When i issue this query 
SELECT EXTRACT(SequenceData, '//VarSequData/VarSequDataRow/VarSequDataColumn/text()').GetClobVal()
  FROM TabL_FileContent
WHERE ROWNUM = 1
/

i get the results in this way.
EXTRACT(SEQUENCEDATA,'//VARSEQUDATA/VARSEQUDATAROW/VARSEQUDATACOLUMN/TEXT()').GE
--------------------------------------------------------------------------------
10.52.5000101010010.52.50001010.52.5000101010010.52.50001010.52.5000101010010.52
.50001010.52.50001010.52.5000101010010.52.50001010.52.50001010.52.50001010.52.50
001010.52.50001010.52.5000101010010.52.500010

I want the results to be in record level one after another.So based on the above example i tried to use XMLSequence but without success.

Here is the query for which i do not get any result.

select extractvalue(value(d), '//VarSequData/VarSequDataRow/VarSequDataColumn')
   from tabl_filecontent x,
         table( xmlsequence( extract(x.sequencedata, '//VarSequData/VarSequDataRow/VarSequDataColumn') ) ) d
where rownum = 1
/

i just get blank. no result.
EXTRACTVALUE(VALUE(D),'//VARSEQUDATA/VARSEQUDATAROW/VARSEQUDATACOLUMN')
----------------------------------------------------------------------------------------------------
I am just attaching a part of the xml file becuae the entire file cannot be pasted here.

<?xml version="1.0" encoding="ISO-8859-1"?>
<MEPSequenceData xmlns="
http://www.w3.org/2001/XMLSchema/XMLAblDaten.xsd"
xmlns:xdb="
http://xmlns.oracle.com/xdb"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.w3.org/2001/XMLSchema/XMLAblDaten.xsd http://www.w3.org/2001/XMLSchema/XMLAblDaten.xsd" <code>Name="CR_SimpleSequencedaten" DataType="Sequencedata" Model="CR" VersionTemplate="1.0" VersionEditor="1.0" LastTimeStamp="20030219132346" LastUpdate="19.02.2003 13.23.46">
<Allgemein>
<AllgemeinRow TimeStamp="20030219132346">
<AllgemeinColumn id="Name" DataType="text">CR_Bedatung_Einschwingen</AllgemeinColumn>
<AllgemeinColumn id="Version" DataType="text">0.1</AllgemeinColumn>
<AllgemeinColumn id="Bemerkung" DataType="text">geaendert von Benutzer: demo</AllgemeinColumn>
<AllgemeinColumn id="letztes Update" DataType="text">19.02.2003 13.23.46</AllgemeinColumn>
</AllgemeinRow>
</Allgemein>
<!-- Teilablaeufe -->
<TA_Sequences>
<Sequence id="TA_01">
<Name>Partsequence PartOne</Name>
<ViewName>PartOne auf Englisch?</ViewName>
<MeasPoint id="TA_01_LPREV_00" Typ="Revolution">
<Name>Emi Revolution</Name>
<ViewName>Emi Revolution...</ViewName>
<PrgIdent>LPREV_01</PrgIdent>
<MeasPointSteps>
<MeasPointStep id="S_001" Nr="1">
<ViewName>Emi Revolution Schritt 1</ViewName>
<StepGeneral>
<StepGeneralRow TimeStamp="20030219132346">
<!--- Diese Daten sind von MeasPoint zu Lastpuntk verschieden
und sind zu jedem Zeitpunkt erweiterbar -->
<StepGeneralColumn id="Lastpunktanzeige" DataType="integer">1</StepGeneralColumn>
<StepGeneralColumn id="EMI_Huebe" DataType="integer">10</StepGeneralColumn>
<StepGeneralColumn id="Messwertaufnahme" DataType="double">1</StepGeneralColumn>
<StepGeneralColumn id="Wartezeit" DataType="double">0</StepGeneralColumn>
</StepGeneralRow>
</StepGeneral>
<SetPhase>
<SetVar id="p_Rail(ASAP)" Unit="bar" DataType="double">
<ViewName>p_Rail(ASAP)</ViewName>
<VarDescription>Hier kann ein beliebiger Text fuer die Beschreibung der Var stehen</VarDescription>
<VarDevice>Emi2</VarDevice>
<!-- dargestellt im Format -->
<DisplayFormat>%8.2f</DisplayFormat>
<!-- 4 Punkte Umrechnungsformel -->
<VarSequData>
<VarSequDataRow TimeStamp="20030219132346">
<VarSequDataColumn id="Sollwert" Unit="" DataType="double">10.5</VarSequDataColumn>
<VarSequDataColumn id="Toleranz" Unit="" DataType="double">2.5</VarSequDataColumn>
<VarSequDataColumn id="Beurteilung" Unit="" DataType="integer">0</VarSequDataColumn>
<VarSequDataColumn id="Bewertung" Unit="" DataType="integer">0</VarSequDataColumn>
<VarSequDataColumn id="Vorverarbeitung" Unit="" DataType="integer">0</VarSequDataColumn>
<VarSequDataColumn id="VorverarbeitungParameter" Unit="" DataType="integer">10</VarSequDataColumn>
<VarSequDataColumn id="Stepweite" Unit="" DataType="integer">10</VarSequDataColumn>
<VarSequDataColumn id="Stepanzahl" Unit="" DataType="integer">100</VarSequDataColumn>
</VarSequDataRow>
</VarSequData>
</SetVar>
</SetPhase>
<MeasPhase>
<MeasVar id="Q_quer(Emi2)" Unit="bar" DataType="double">
<ViewName>Q_quer(Emi2)</ViewName>
<VarDescription>Hier kann ein beliebiger Text fuer die Beschreibung der Var stehen</VarDescription>
<VarDevice>Emi2</VarDevice>
<VarSequData>
<VarSequDataRow TimeStamp="20030219132346">
<VarSequDataColumn id="Sollwert" Unit="" DataType="double">10.5</VarSequDataColumn>
<VarSequDataColumn id="Toleranz" Unit="" DataType="double">2.5</VarSequDataColumn>
<VarSequDataColumn id="Beurteilung" Unit="" DataType="integer">0</VarSequDataColumn>
<VarSequDataColumn id="Bewertung" Unit="" DataType="integer">0</VarSequDataColumn>
<VarSequDataColumn id="Vorverarbeitung" Unit="" DataType="integer">0</VarSequDataColumn>
<VarSequDataColumn id="VorverarbeitungParameter" Unit="" DataType="integer">10</VarSequDataColumn>
</VarSequDataRow>
</VarSequData>

Can you kindly help me out with this problem.



Should i place this question in new thread ?

Raghu, February 23, 2004 - 12:10 am UTC

Hi Tom,

Do i need to put the above question in a new thread.
I have posted it here becuase in the above discussions XMLSequence is being discussed.

Please let me know.


Tom Kyte
February 23, 2004 - 7:38 am UTC

I do not see all reviews -- and I cannot answer all of them either.

I asked someone else to look at this, xml is not my area of expertise, if they get time, they will.

Problem is solved.

Raghu, February 25, 2004 - 6:15 am UTC

i am posting this so that others can benefit from this.

In such situations you can provide namespace along with the xpath to EXTRACT and EXTRACTVALUE operators.

Here is the query.
SELECT EXTRACTVALUE(VALUE(x), '/StepGeneralColumn[@DataType="KonfigFile"]', 'xmlns="</code> http://www.w3.org/2001/XMLSchema/XMLAblDaten.xsd"'
  FROM TabL_FileContent
, TABLE(XMLSEQUENCE(EXTRACT(SequenceData, '/MEPSequenceData//StepGeneralColumn', 'xmlns="
http://www.w3.org/2001/XMLSchema/XMLAblDaten.xsd"' <code>)) x
WHERE FileID = 1
/


Setting the dateformat using DBMS_XMLGEN

Nolan Tucker, March 09, 2004 - 4:56 pm UTC

Hi Tom and Sean,
This thread has lots of useful information. Thank you.

We're using dbms_xmlgen and passing it a resultset from a stored procedure. I'd like date fields generated in 'YYYY-MM-DD HH24:MM:SS' format. I don't see a procedure like
dbms_xmlgen.usenullattributeindicator that will do this. Can this be influenced by setting the session nls_date_format? If not how do I format? We're running Oracle9i Enterprise Edition Release 9.2.0.4.0.

This is a simplified version of what we're doing:
declare
test_cursor HDP_LocationDetail_PAK.LocationDetailCur;
resultset test_cursor%rowtype;
resultset_xml XMLTYPE;
resultsetrows integer;
resultsetsize integer;
l_ctx dbms_xmlgen.ctxHandle;
begin
HDP_LocationDetail_PRC(test_cursor,'Valexia','101815',TO_DATE('2003-05-15', 'YYYY-MM-DD'), TO_DATE('2003-06-30', 'YYYY-MM-DD');
l_ctx := dbms_xmlgen.newContext(test_cursor);
dbms_xmlgen.usenullattributeindicator(l_ctx,TRUE);
resultset_xml := dbms_xmlgen.getxml(l_ctx);
resultsetrows := dbms_xmlgen.getNumRowsProcessed(l_ctx);

dbms_output.put_line(''rowsprocessed=''||resultsetrows);

UPDATE vrp_ReportRuns SET enddate=SYSDATE, rowsreturned=resultsetrows,reportresultset=resultset_xml,
statuscode=0,statusmessage=''Success'',
nextrundate=NULL, failurecount=0;

dbms_xmlgen.closeContext(l_ctx);

commit;
end;

Thank you for your time.
Nolan

Okay - yes it works.

Nolan Tucker, March 18, 2004 - 4:39 pm UTC

I altered my session at the beginning of the procedure with
DBMS_SESSION.SET_NLS('NLS_DATE_FORMAT','''YYYY-MM-DD HH24:MI:SS''');
and found the XML datetype nodes are stored as 'YYYY-MM-DD HH24:MI:SS'.

XML extraction alternatives?

J, May 14, 2004 - 11:24 am UTC

Hello Tom.

Thanks for your services to the Oracle community (it's Most Appreciated). I have a situation like this: (sql*plus: 9.2.0.1.0, Database: 9.2.0.4.0)

create table jtest2
(p number primary key,
other_columns_etc varchar2(20),
r number);

begin
for i in 1..100
loop
execute immediate
'insert into jtest2(p) values (:val)'
using i;
end loop;
commit;
end;

-- --------------------------------------------------------
-- So create an xmlarray of JTEST2 rows that have null R's.
-- This array is passed to an RPC-procedure that figures
-- out the R's, and passes back the array with R values.
--
-- The following pseudo-replicates the returned array...
-- --------------------------------------------------------

declare
v_xml xmltype;

type tt_p is table of jtest2.p%type;
tab_p tt_p := tt_p();

type tt_r is table of jtest2.r%type;
tab_r tt_r := tt_r();
begin
select xmlelement
("SET",
(select xmlagg(xmlelement("ROW",xmlattributes(P,R)))
from
(select P,
other_columns_etc,
12 R -- mimics returned value
from jtest2
where r is null)
)
)
into v_xml
from dual;

-- -----------------------------------------------------
-- The XML string looks like this...
-- In real life (??), there's fluff attributes
-- in here that I don't care about.
--
-- <SET><ROW P="1" R="12"></ROW><ROW P="2" R="12"></ROW>
-- etc... </SET>
-- -----------------------------------------------------

-- Some stuff happens here...

-- -----------------------------------------------------
-- Load up P and R arrays.
-- These arrays are later used in a forall to go back
-- and update JTEST2.R columns (matching on P).
--
-- This takes about *82%* of the total procedural time.
-- (with 85k+ rows and full data regalia)
--
-- THE QUESTION (finally):
-- Are there any other approaches that I can use
-- to speed this up? I tried bulking into a type,
-- and ran a slug-o-tests, but no appreciable
-- difference in dbms_utility.get_time results
-- compared to this method.
-- -----------------------------------------------------

for xml_rec in
(select extractvalue(value(t),'/ROW@P') p,
extractvalue(value(t),'/ROW@R') r
from table(xmlsequence(v_xml.extract('/SET/ROW'))) t
)
loop
if (xml_rec.r is not null) then
tab_p.extend;
tab_p(tab_p.count) := xml_rec.p;
tab_r.extend;
tab_r(tab_r.count) := xml_rec.r;
end if;
end loop;

-- Then Forall update, More Stuff Happens, etc.
-- Thanks for your time, have a great weekend!!! - J
end;

XML Extraction Alternatives (part deux)

J, May 14, 2004 - 4:24 pm UTC

Hello Tom.

FYI, here's what has been tried so far:
1) Bulk load the extractvalue-related query into a tabtype based on an object type.
2) Bulk load the data into two procedure-defined arrays.
3) Load via a cursor "for" loop into two arrays.
4) Load via a cast/multiset (whoa, that was a slow one).

All of my attempts (except for #4) yield the same approximate throughput - about 100 rows/sec. I reduced the number of non-necessary attributes (leaving the returned xmltype with just the "P" and "R" attributes). That seemed to pick things up a bit, but only by 5-7% (which could be influenced by the fact that this is a shared Dev environment).

So... I'm wondering if this throughput rate is consistent with experiences using the extractvalue/xmlsequence method used above. Is there another option for extracting out specific attributes in an xml doc that might be quicker?

Many thanks!
- J

XML Extraction Alternatives

J, May 20, 2004 - 9:53 am UTC

G'Morning Tom.

Hope things are going well for you at the client site. Must be a good'un! I was wondering if you had any thoughts about the throughput rate for the:

select extractvalue(value(t),'/ROW@P') p,
extractvalue(value(t),'/ROW@R') r
from table(xmlsequence(lv_xml.extract('/SET/ROW'))) t

question. It's workable, but... are there other approaches? We ran a dbms_profiler on the process, and yep, about 82% of the total procedural time is spent on this one select statement. Tried the above-mentioned approaches and the times were similar. Am I missing anything, any parameters I should look at, can this be parallelized (if that's a word), etc? Thanks again.

- J

Tom Kyte
May 20, 2004 - 11:43 am UTC

well, if those were values I needed LOTS, i might consider extracting that out during the INSERT (since you insert once and query many many times)

Where is the class oracleXML ?

Randy King, May 20, 2004 - 3:43 pm UTC

Getting error while doing java OracleXML getXML -user "scott/tiger" "select * from emp where rownum < 5"
Exception in thread "main" java.lang.NoClassDefFoundError: OracleXML

I already installed xdk.

Tom Kyte
May 20, 2004 - 8:14 pm UTC

what's your classpath set to.

How to Seperate Concat Values

MSU, September 13, 2004 - 9:48 am UTC

Hi Tom and Sean,

SQL> desc order_formats

Name           Null?        Type
ORDER_ID       NOT NULL     NUMBER(18)
ORDER_XML      NOT NULL     SYS.XMLTYPE


Here is a sample query

select order_xml from order_formats where order_id=2055169;

And the result is this

<cXML timestamp="2004-09-06T11:05::13">
<Request>
<OrderRequest>
<ItemOut quantity="12" lineNumber="9">
<ItemID>                                           <SupplierPartID>054054</SupplierPartID>
</ItemID>        
</ItemOut>
<ItemOut quantity="10" lineNumber="10">
<ItemID>
<SupplierPartID>30054054</SupplierPartID>
</ItemID>
</ItemOut>
</OrderRequest>
</Request>
</cXML>

When I write a select query as

SELECT
order_id,
formats.order_xml.extract('/cXML/Request/OrderRequest/ItemOut/ItemID/SupplierPartID').getStringVal() SupplierID
FROM
ORDER_FORMATS formats
WHERE formats.order_id=2055169

I get the result as


  ORDER_ID SUPPLIERID
---------- -----------------------------------------
   2055169 <SupplierPartID>054054</SupplierPartID>
           <SupplierPartID>30054054</SupplierPartID>


When I use text() in the query as mentioned below

 SELECT
 order_id,
 formats.order_xml.extract('/cXML/Request/OrderRequest/ItemOut/ItemID/SupplierPartID/text()').getStringVal() SupplierID
 FROM
 ORDER_FORMATS formats
 WHERE formats.order_id=2055169

Both the values inside the tag get concat

  ORDER_ID SUPPLIERID
---------- ----------------
   2055169 05405430054054

which I dont want. I want the result to be 2 numbers which are comma seperated. How to achieve the same. Thanking you in advance. 

Tom Kyte
September 13, 2004 - 11:24 am UTC

select order_id || ',' || formats.order_xml.extract( ......



Comma seperated Values - Corrected Query

MSU, September 14, 2004 - 2:32 am UTC

Hi Tom,

At the outset my apologies for an ambiguous query posted last time,which I have corrected while posting this one.

In my XML I have more than one tag which are having the same name. Suppose I want to extract them all with a comma seperating them how do I do that.

In the sample which I had given I have 2 SupplierPartID.

When I write a query without using text() I get the values along with the tags.

SELECT
formats.order_xml.extract('//SupplierPartID').getString
FROM
ORDER_FORMATS formats
WHERE formats.order_id=2055169

The answer is as follows

SUPPLIERID
-----------------------------------------
<SupplierPartID>054054</SupplierPartID>
<SupplierPartID>30054054</SupplierPartID>

When I rewrite the same query with the text()

SELECT
formats.order_xml.extract
('//SupplierPartID/text()').getStringVal() SupplierID
FROM
ORDER_FORMATS formats
WHERE formats.order_id=2055169

The answer is like the one below.

SUPPLIERID
---------------
05405430054054

Both the values with the same tag - <SupplierPartID> get concat. I want these two values namely 054054 AND 30054054 to be comma seperated. How to achieve the same. Thanking you in anticipation.

Tom Kyte
September 14, 2004 - 6:46 pm UTC

I asked Sean, my XML guy, to take a look at this and here's what he had to say:
--

hi MSU,

This is pretty easy to do, you have a couple of options.  First, you can use standard XSLT to do this inside the database.  The XMLTYPE datatype has a member method (function) called TRANSFORM that will allow you to use any XSL stylesheet on your XML.  If you google XSLT comma separated values, you'll find LOTS of stylesheets out there to help you write those.

You can also use DOM inside the database.  So for instance, I might use the following code snippet to get a DOM document, get a list of DOM nodes, iterate over those nodes, and concatenate the values into a CSV that gets returned in a function:

----------------
SQL> create table t ( order_xml sys.xmltype );
Table created.

SQL> insert into t values ( xmltype(
  2  '<x><SupplierPartID>123</SupplierPartID>
  3      <SupplierPartID>456</SupplierPartID>
  4      <SupplierPartID>789</SupplierPartID>
  5      <SupplierPartID>abc</SupplierPartID>
  6      <SupplierPartID>def</SupplierPartID>
  7  </x>') );
1 row created.

SQL> create or replace function supplierList( p_xml XMLType ) return varchar2
  2  is
  3    l_supplier      dbms_xmldom.DOMNode;
  4    l_supplierElts  dbms_xmldom.DOMNodeList;
  5    l_supplierCnt   pls_integer;
  6    l_curSupplier   dbms_xmldom.DOMNode;
  7    l_csv           clob;
  8    l_val           varchar2(100);
  9  begin
 10    l_supplier := dbms_xmldom.makeNode(dbms_xmldom.newDOMDocument(p_xml));
 11    l_supplierElts := dbms_xslprocessor.selectNodes(l_supplier,'/x/SupplierPa
 12    l_supplierCnt  := dbms_xmldom.getLength(l_supplierElts);
 13    
 14    for pos in 1..l_supplierCnt loop
 15      l_curSupplier   := dbms_xmldom.item(l_supplierElts,pos-1);
 16      dbms_xslprocessor.valueOf(l_curSupplier,'text()',l_val);
 17      l_csv := l_csv || l_val;
 18      if pos <> l_supplierCnt then l_csv := l_csv || ','; end if;
 19    end loop;
 20    return l_csv;
 21  end;
 22  /
Function created.

SQL> select supplierList(order_xml)
  2    from t
  3  /

SUPPLIERLIST(ORDER_XML)
-----------------------------
123,456,789,abc,def


Hope that helps! 

Error occurred in XML processing

MSU, September 15, 2004 - 9:20 am UTC

Hi Tom And Sean,

At the ouset thankyou very much for such a wonderful website.The DOM and XSLT methods for my above mentioned problem were really very useful to me. Since I am using a database with sys.xml type for the first time. I come across different types of errors / doubts every now and then. Today I came across one such. Please do have a look at the sample code below.

SQL> create table t ( order_xml sys.xmltype );
Table created.

SQL> desc t
 Name          Null?    Type

ORDER_XML               SYS.XMLTYPE



SQL> ed
Wrote file afiedt.buf

  1  insert into t values ( SYS.XMLType.createXML('<?xml version="1.0" ?>
  2    <ItemOut>
  3    <ItemID>
  4    <Description xml:lang="en"> SMOOTH PAPER 123 </Description>
  5    <SupplierPartID>123</SupplierPartID>
  6    </ItemID>
  7*  </ItemOut>'))
SQL> /

1 row created.



SQL> select * from t;

ORDER_XML
---------
<ItemOut>
  <ItemID>
    <Description xml:lang="en">SMOOTH PAPER 123 </Description>
    <SupplierPartID>123</SupplierPartID>
  </ItemID>
</ItemOut>


SELECT 
T1.extract('/ItemOut/ItemID/SupplierPartID/text()').getStringVal()
SupplierID
FROM t, 
TABLE(XMLSEQUENCE(EXTRACT(order_xml,'//ItemOut'))) T1


SELECT
*
ERROR at line 1:
ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00233: namespace prefixes starting with "xml" are reserved
Error at line 3
ORA-06512: at "SYS.XMLSEQ_IMP_T", line 7
ORA-06512: at "SYS.XMLSEQ_IMP_T", line 7

At the same time if my <Description> is plain (Without any XML:lang="en") The same query runs perfectly. Which I have given below

SQL> delete from t;

1 row deleted.

SQL> ed
Wrote file afiedt.buf

  1  insert into t values ( SYS.XMLType.createXML('<?xml version="1.0" ?>
  2  <ItemOut>
  3  <ItemID>
  4  <Description> SMOOTH PAPER 123 </Description>
  5  <SupplierPartID>123</SupplierPartID>
  6  </ItemID>
  7* </ItemOut>'))
  8  /

1 row created.

SQL> select * from t;

ORDER_XML
---------
<ItemOut>
  <ItemID>
    <Description>SMOOTH PAPER 123 </Description>
    <SupplierPartID>123</SupplierPartID>
  </ItemID>
</ItemOut>


SQL> ed
Wrote file afiedt.buf

  1  SELECT
  2  T1.extract('/ItemOut/ItemID/SupplierPartID/text()').getStringVal()
  3  SupplierID
  4  FROM t,
  5* TABLE(XMLSEQUENCE(EXTRACT(order_xml,'//ItemOut'))) T1
SQL> /

SUPPLIERID
-----------

123

I wish to know what exactly is the error and how to overcome this. Thanking you in anticipation.
 

Tom Kyte
September 15, 2004 - 5:20 pm UTC

Sean Dillon here...
--

Well, you actually have a couple of problems.  First of all, XML is a reserved namespace.  You can't use it for your own custom namespace declaration.  You can check into the W3C XML standard for reserved namespaces (not sure of others but I'm sure if I say there aren't any there will be), but clearly XML is one of them.

Second, even if you used a non-reserved word for your namespace, your XML document isn't well-formed as there is no namespace declaration.  Consider...

SQL> create table t ( order_xml sys.xmltype );
Table created.

-- YOUR PROBLEM, YOU CAN'T USE THE XML NAMESPACE EVEN IF YOU DECLARE IT:
SQL> insert into t values ( SYS.XMLType.createXML('<?xml version="1.0" ?>
  2    <ItemOut xmlns:xml="
http://www.oracle.com" >
  3    <ItemID>
  4    <Description xml:lang="en"> SMOOTH PAPER 123 </Description>
  5    <SupplierPartID>123</SupplierPartID>
  6    </ItemID>
  7   </ItemOut>'));
insert into t values ( SYS.XMLType.createXML('<?xml version="1.0" ?>
                       *
ERROR at line 1:
ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00233: namespace prefixes starting with "xml" are reserved
Error at line 2
ORA-06512: at "SYS.XMLTYPE", line 54
ORA-06512: at line 1

-- THIS SQL INSERT SHOWS THE NEXT PROBLEM, NOT USING A RESERVED WORD (XSI) BUT
-- NOT DECLARING THE XSI NAMESPACE:
SQL> insert into t values ( SYS.XMLType.createXML('<?xml version="1.0" ?>
  2    <ItemOut>
  3    <ItemID>
  4    <Description xsi:lang="en"> SMOOTH PAPER 123 </Description>
  5    <SupplierPartID>123</SupplierPartID>
  6    </ItemID>
  7   </ItemOut>'))
  8  /
insert into t values ( SYS.XMLType.createXML('<?xml version="1.0" ?>
                       *
ERROR at line 1:
ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00234: namespace prefix "xsi" is not declared
Error at line 4
ORA-06512: at "SYS.XMLTYPE", line 54
ORA-06512: at line 1

-- HERE, WE DECLARE THE XSI NAMESPACE AND WE USE IT APPROPRIATELY, NO PROB:
SQL> insert into t values ( SYS.XMLType.createXML('<?xml version="1.0" ?>
  2    <ItemOut xmlns:xsi="
http://www.oracle.com" >
  3    <ItemID>
  4    <Description xsi:lang="en"> SMOOTH PAPER 123 </Description>
  5    <SupplierPartID>123</SupplierPartID>
  6    </ItemID>
  7   </ItemOut>'));
1 row created.

SQL> select * from t;

ORDER_XML
--------------------------------------------------------------------------------
<?xml version="1.0" ?>
  <ItemOut xmlns:xsi="
http://www.oracle.com" >
  <ItemID>
...etc...

Hope that helps!

_Sean Dillon_
 

XML Output

Sudip Sarkar, September 15, 2004 - 10:57 am UTC

Hi Tom,
I have a requirement where I have to take out data from two tables (Master and Detail), the output needs to be in XML format.
The attributes from the detail table will be repeating, Is it possible to produce this kind of output using dbms_xmlquery package?

Order Master Table
Order_ID Order_Date
1 12/10/2004
2 11/10/2004

Order Detail Table
Order_ID Item_number QTY
1 ITM01 4
1 ITM02 1
1 ITM03 3
1 ITM04 5

The following is the output need
Order_Id
Order_date
Item_number -- this is multiple for each order
QTY -- this is multiple for each order

Thanks

XMLTYPE()

A reader, September 15, 2004 - 1:50 pm UTC

FYI. To the user above who was hitting the XMLTYPE() response when trying to run a SQLX statement.. It's the version of SQL*Plus you use.

9204 returns the goods fine.

901x doesn't.

Assigning Value Inside an Tag to a variable

MSU, September 22, 2004 - 9:20 am UTC

Hello Tom,

Thanks a million for such a wonderful site. Tom please do have look at the folowing 


SQL> create table my_table ( x int, y sys.xmltype );

Table created.

SQL> insert into my_table values ( 1, xmltype( '<A>Aa<B>Bb<C>ABC</C></B></A>'));

1 row created.

SQL> select msu.y.extract('/A/B/C/text()').getstringval() from my_table msu;

MSU.Y.EXTRACT('/A/B/C/TEXT()').GETSTRINGVAL()
--------------------------------------------------------------------------------
ABC

SQL> ed
Wrote file afiedt.buf

  1  DECLARE
  2  v_val SYS.XMLTYPE;
  3  cursor c_table_update is
  4  select msu.y.extract('/A/B/C/text()').getstringval() val from my_table msu;
  5  BEGIN
  6     open c_table_update;
  7             loop
  8                     fetch c_table_update into v_val ;
  9                     exit when c_table_update%notfound;
 10                     dbms_output.put_line(to_char(v_val));
 11             END LOOP;
 12     CLOSE c_table_update;
 13* END;
SQL> /
                        fetch c_table_update into v_val ;
                                                  *
ERROR at line 8:
ORA-06550: line 8, column 30:
PLS-00386: type mismatch found at 'V_VAL' between FETCH cursor and INTO variables
ORA-06550: line 8, column 4:
PL/SQL: SQL Statement ignored
ORA-06550: line 10, column 25:
PLS-00306: wrong number or types of arguments in call to 'TO_CHAR'
ORA-06550: line 10, column 4:
PL/SQL: Statement ignored


(1) What is the meaning of the 2 ORACLE Error messages which I am getting and more importantly why am I getting this error inspite of declaring the variable as sys.xmltype.

(2) Where am I going wrong ?

(3) How to assign the value of the XML node which has been extracted into a variable. Do let me know. Thanking you in anticipation 

Tom Kyte
September 22, 2004 - 10:08 am UTC

1) means the data type you are fetching into doesn't match that which you are fetching and cannot be converted implicitly.

It is because you made it xmltype, that it is failing.  Here is what I do to see "what are the types" really quick:


ops$tkyte@ORA9IR2> create or replace view vw
  2  as
  3  select msu.y.extract('/A/B/C/text()').getstringval() data from my_table msu;
 
View created.
 
ops$tkyte@ORA9IR2> desc vw
 Name                                     Null?    Type
 ---------------------------------------- -------- ----------------------------
 DATA                                              VARCHAR2(4000)
 

getStringval returns a STRING -- not an xmltype!

I would just code:

for x in ( your query here )
loop
   use x.attribute ....
end loop;


explicit cursors are a pain in the butt. 

"Error occurred in XML processing - II"

MSU, September 23, 2004 - 9:10 am UTC

Hi Tom and Sean,
At the very outset thanks a million for such a wonderful site. Thanks again for the detailed answer to my query "Error occurred in XML processing"

Please do have a look at the below mentioned code

SQL> create table t ( order_xml sys.xmltype );
Table created.

SQL> desc t
 Name          Null?    Type

ORDER_XML               SYS.XMLTYPE



SQL> ed
Wrote file afiedt.buf

  1  insert into t values ( SYS.XMLType.createXML('<?xml version="1.0" ?>
  2    <ItemOut>
  3    <ItemID>
  4    <Description xml:lang="en"> SMOOTH PAPER 123 </Description>
  5    <SupplierPartID>123</SupplierPartID>
  6    </ItemID>
  7*  </ItemOut>'))
SQL> /

1 row created.



SQL> select * from t;

ORDER_XML
---------
<ItemOut>
  <ItemID>
    <Description xml:lang="en">SMOOTH PAPER 123 </Description>
    <SupplierPartID>123</SupplierPartID>
  </ItemID>
</ItemOut>


SELECT 
T1.extract('/ItemOut/ItemID/SupplierPartID/text()').getStringVal()
SupplierID
FROM t, 
TABLE(XMLSEQUENCE(EXTRACT(order_xml,'//ItemOut'))) T1


SELECT
*
ERROR at line 1:
ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00233: namespace prefixes starting with "xml" are reserved
Error at line 3
ORA-06512: at "SYS.XMLSEQ_IMP_T", line 7
ORA-06512: at "SYS.XMLSEQ_IMP_T", line 7

To overcome this problem you had suggested me to use XSI namespace instead of XML Namespace. But I have a situation where in I have about 100K entries  in my Table ( In turn 100K XML scripts) which are having XML Namespace. 

Moreover I have to work(query) the scripts which are in the above mentioned format - Having XML Namespace. I am not allowed to change the scripts. Is there anyway I can query such scripts having XML namespace and get an answer ?

If the above mentioned is impossible and also assuming that I am allowed to change the name space(From XML to XSI) in my XML scripts how to proceed to achieve the same.

Thanking you in anticipation. 

XMLType and Embedded pdf

Govind Agnihotri, October 11, 2004 - 2:25 pm UTC

I have a XML with a embedded .pdf ( Base64 encoded) in a Document Cdata tag?
I could get all the other tags using Xpath expressions, How do your get the pdf section and store it in a blob. When I get Stringval '<DOCUMENT>', [CDATA[', ']]></DOCUMENT> are a part of the string.
The pdf viewer complains the document contains non-base64 string?
Do you have any API's to extract CDATA sections in XMLtype?

Thanks in advance,
Govind.




Who is eating my CRLF's??!!

Nemec, February 01, 2005 - 7:29 am UTC

I've a very simple problem, but I can't find the solution. So please help:
Using xmlelement I get

SQL> SELECT XMLELEMENT("Emp", XMLELEMENT("name", 'Abbbbb'),                     
                           XMLELEMENT ( "hiredate", '01011900')) AS "result"    
FROM dual  2    3  ;                                                            
                                                                                
result                                                                          
--------------------------------------------------------------------------------
<Emp><name>Abbbbb</name><hiredate>01011900</hiredate></Emp>                     
                                                                                
SQL> 

I'd like to get somthing like that (examples in manuals are in that form)

<Emp>
 <name>Abbbbb</name>
 <hiredate>01011900</hiredate>
</Emp>
     

Other question. How could I generate the <?xml version="1.0"?> line on the top of the document?


Thanks

Jaromir 

Tom Kyte
February 01, 2005 - 9:51 am UTC

SQL> select xmltype.createxml('<?xml version="1.0"?>' ||
  2           xmlelement("Emp",
  3             xmlforest('Abbbbb' as "name",
  4                       '01011900' as "hiredate")
  5           )
  6         )
  7    from dual
  8  /

XMLTYPE.CREATEXML('<?XMLVERSION="1.0"?>'||XMLELEMENT("EMP",XMLFOREST('ABBBBB'AS"
--------------------------------------------------------------------------------
<?xml version="1.0"?><Emp><name>Abbbbb</name><hiredate>01011900</hiredate></Emp>
 

SQL*Plus formats XML

Tak Tang, February 01, 2005 - 11:41 am UTC

In response to Nemec/Jaromir from Tabor . . .

SQL*Plus is the thing that formats the XMLTYPE. In the past, my XML came out as a serialised string (as your's has), but it is currently comming out nicely formatted (like the manuals). I'm not sure whether this is due to which version of SQL*Plus I am running (SQL*Plus: Release 9.2.0.1.0 - Production), or if it is a SETting.

'SQL*Plus: Release 8.0.6.0.0 - Production' crashes with XMLTYPE, and a popular third party tool returns '(ORAXML)'.

Tak


thank you

mar, February 03, 2005 - 7:53 pm UTC

thank you for the good helps that you give it to the students like me .

i wish you luck .

for give me for that bad lunguage.

convert to flat cvs file first, and then convert to xml for better performance

Jim, February 15, 2005 - 1:28 am UTC

If large tables with a lot of data, then tools that allow quickly extract tables into csv files and generate XML then will be useful for that purpose.

I know FastReader can convert large Oracle tables into xml files in efficient way. Probably some other tools do similar.
wisdomforce Fastreader that I mentioned can be found at www.wisdomforce.com

relational query from xmltype column

Nilanjan Ray, February 16, 2005 - 8:05 am UTC

I have created the following table:

CREATE TABLE test_xml_tab(
poid number,
pDoc XMLTYPE);

created directory :
CREATE DIRECTORY xmlfiles AS '/appl/oracle/xmldata';

created function
create or replace function fileToClob(fname varchar2) return clob is
fclob clob;
theBFile BFILE;
begin
dbms_lob.createtemporary(fclob,false,DBMS_LOB.SESSION);

theBFile := BFileName('XMLFILES',fname);

dbms_lob.fileOpen(theBFile);

dbms_lob.loadFromFile(fclob,
theBFile,
dbms_lob.getLength(theBFile));
dbms_lob.fileClose(theBFile);
return fclob;
end;
/

loaded xml:
INSERT INTO test_xml_tab VALUES (100, XMLType(fileToClob('txml.xml')));

sample data:
- <Response>
- <ACResponse>
- <CommonDataResponse>
- <CommonMandatoryResponse HcsTcsInd="T" LangInd="00" MessageType="A" TzCode="705" Version="2">
<MerchantID>123456789012</MerchantID>
<TerminalID>001</TerminalID>
<TxRefNum>128E6C6A4FC6D4119A3700D0B706C51EE26DF570</TxRefNum>
<TxRefIdx>0</TxRefIdx>
<OrderNumber>1234567890123456</OrderNumber>
<RespTime>10012001120003</RespTime>
<ProcStatus>0</ProcStatus>
<ApprovalStatus>1</ApprovalStatus>
- <ResponseCodes>
<AuthCode>tntC09</AuthCode>
<RespCode>00</RespCode>
<HostRespCode>00</HostRespCode>
<CVV2RespCode>M</CVV2RespCode>
<HostCVV2RespCode>M</HostCVV2RespCode>
<AVSRespCode>H</AVSRespCode>
<HostAVSRespCode>Y</HostAVSRespCode>
</ResponseCodes>
- <ResponseCodes>
<AuthCode>tntC091</AuthCode>
<RespCode>00</RespCode>
<HostRespCode>00</HostRespCode>
<CVV2RespCode>M</CVV2RespCode>
<HostCVV2RespCode>M</HostCVV2RespCode>
<AVSRespCode>H</AVSRespCode>
<HostAVSRespCode>Y</HostAVSRespCode>
</ResponseCodes>
- <ResponseCodes>
<AuthCode>tntC092</AuthCode>
<RespCode>00</RespCode>
<HostRespCode>00</HostRespCode>
<CVV2RespCode>M</CVV2RespCode>
<HostCVV2RespCode>M</HostCVV2RespCode>
<AVSRespCode>H</AVSRespCode>
<HostAVSRespCode>Y</HostAVSRespCode>
</ResponseCodes>
</CommonMandatoryResponse>
- <CommonOptionalResponse>
<AccountNum>4012888888881</AccountNum>
<RespDate>010801</RespDate>
<CardType>VI</CardType>
<ExpDate>200512</ExpDate>
<CurrencyCd>840</CurrencyCd>
</CommonOptionalResponse>
</CommonDataResponse>
- <AuthResponse>
<AuthMandatoryResponse />
- <AuthOptionalResponse>
<POSEntryMode>01</POSEntryMode>
- <MISCData>
<ActualRespCd>00</ActualRespCd>
</MISCData>
- <NetworkData>
<AuthNetwkID>01</AuthNetwkID>
</NetworkData>
- <VisaCard>
- <CPSData>
<AuthCharInd>V</AuthCharInd>
<ValidationCd>JU9E</ValidationCd>
</CPSData>
<AuthSource AuthSrc="5" />
<VisaCommCard VCC="S" />
</VisaCard>
</AuthOptionalResponse>
</AuthResponse>
</ACResponse>
</Response>

My question is, how do I use a select statement to retrive all the records in relational format from the xmltype column?

Regards



Tom Kyte
February 16, 2005 - 10:02 am UTC

I asked Sean Dillon to take a look at this, here's what he had to say:
--

Fortunately, we document stuff like this. I suggest you look at these URL's for more information on querying XML data:

XML DB Developer's Guide : </code> http://docs.oracle.com/docs/cd/B14117_01/appdev.101/b10790/toc.htm
(See Chapter 3 Using XML DB, specifically the section on "Querying XML Content Stored in Oracle XML DB".  I recommend anybody using XML DB read through this entire document, it's incredibly helpful in understanding how XML DB works and how to employ it properly.)

XML DB Technology Center on OTN : 
http://www.oracle.com/tech/xml

XML DB sample code (download/install/run the "Oracle9i R2 XML DB Demonstration", it'll help you tremendously):
http://www.oracle.com/technology/sample_code/tech/xml/xmldb/index.html <code>

Hope that helps,

_smd_
Sean Dillon

relational query from xmltype column-extractvalue(..)

Nilanjan Ray, February 17, 2005 - 6:11 am UTC

Thanks Tom/Sean,

I was able to do it by going through Oracle doc. Amazing stuff!!! I have been using Oracle since ver 7. 9i is awesome, 10g is definitely more !!!!!

One simple question though...

Using the following data.
<?xml version = '1.0' encoding = 'UTF-8'?>
<ROWSET>
<ROW>
<START_TM>284659</START_TM>
<EVENT_NM><![CDATA[The People'S Book Of Records # 1]]></EVENT_NM>
<MODIFY_BY>SYSTEM</MODIFY_BY>
</ROW>
<ROW>
<START_TM>284659</START_TM>
<EVENT_NM><![CDATA[The People'S Book Of Records # 1]]></EVENT_NM>
<MODIFY_BY>SYSTEM</MODIFY_BY>
</ROW>
<ROWSET>

Using the foloowing SQL I can extract the value of one column:

SELECT extractValue(value(t),'/START_TM') start_tm
FROM XMLTABLE X,
TABLE (
xmlsequence ( extract(value(X),'/ROWSET/ROW/START_TM') )
) t

I would like to select all the values of START_TM,EVENT_NM and MODIFY_BY in a single statement in column format.

START_TM EVENT_NM MODIFY_BY
-------- -------- ---------
284659 The People'S Book Of Records SYSTEM
284660 The Joy # 1 SYSTEM

Please suggest.

Regards



Tom Kyte
March 04, 2005 - 9:53 am UTC

I asked Sean Dillon to take a look at this, here's what he had to say:
--

You just need to select the XMLSEQUENCE at a higher level in the node tree, and specify the sub-elements in your extractvalue statements:

SQL> create table xmltest of xmltype
  2  /
Table created.

SQL> insert into xmltest values(
  2  xmltype(
  3  '<?xml version = "1.0" encoding = "UTF-8"?>
  4  <ROWSET>
  5    <ROW>
  6      <START_TM>284659</START_TM>
  7      <EVENT_NM><![CDATA[The People''s Book Of Records # 1]]></EVENT_NM>
  8      <MODIFY_BY>SYSTEM</MODIFY_BY>
  9    </ROW>
 10    <ROW>
 11      <START_TM>284659</START_TM>
 12      <EVENT_NM><![CDATA[The People''s Book Of Records # 1]]></EVENT_NM>
 13      <MODIFY_BY>SYSTEM</MODIFY_BY>
 14    </ROW>
 15  </ROWSET>'))
 16  /
1 row created.

SQL> col start_tm for a10
SQL> col event_nm for a40
SQL> col modify_by for a20
SQL> select extractValue(value(t),'/ROW/START_TM') start_tm,
  2         extractValue(value(t),'/ROW/EVENT_NM') event_nm,
  3         extractValue(value(t),'/ROW/MODIFY_BY') modify_by
  4    from xmltest x,
  5         table ( xmlsequence ( extract(value(x),'/ROWSET/ROW') ) ) t
  6  /

START_TM   EVENT_NM                                 MODIFY_BY
---------- ---------------------------------------- --------------------
284659     The People's Book Of Records # 1         SYSTEM
284659     The People's Book Of Records # 1         SYSTEM

 

Where clause in XML query?

Tony, February 25, 2005 - 10:13 am UTC

Tom,

What I want out is basically
<ProductList>
<Product>
<Main></Main>
<Modified></Modified>
<EnduranceList>
<Endurance>
<EnduranceName></EnduranceName>
<EnduranceSpec></EnduranceSpec>
<EnduranceRoll></EnduranceRoll>
<Endurance/>
<Endurance>
<EnduranceName></EnduranceName>
<EnduranceSpec></EnduranceSpec>
<EnduranceRoll></EnduranceRoll>
<Endurance/>
<Endurance>
<EnduranceName></EnduranceName>
<EnduranceSpec></EnduranceSpec>
<EnduranceRoll></EnduranceRoll>
<Endurance/>
<Endurance>
<EnduranceName></EnduranceName>
<EnduranceSpec></EnduranceSpec>
<EnduranceRoll></EnduranceRoll>
<Endurance/>
<Endurance>
<EnduranceName></EnduranceName>
<EnduranceSpec></EnduranceSpec>
<EnduranceRoll></EnduranceRoll>
<Endurance/>
</EnduranceList>
</Product>
</ProductList>

With values inbetween the tags.

And this is what I use to generate it:

select xmlelement("ProductList",
(SELECT xmlagg(xmlelement ("Product", xmlforest (p.main as "Main", p.modified
as "Modified"),
xmlelement ("EnduranceList",
(SELECT xmlagg(xmlelement("Endurance", xmlforest (

DECODE (q,
1, 'Main',
2, 'Sub',
3, 'Cat',
4, END01,
5, END02
) AS "EnduranceName",
DECODE (s,
1, Main,
2, Sub,
3, Cat,
4, "Value01",
5, "Value02"
) AS "EnduranceSpec",
DECODE (r,
1, null,
2, null,
3, null,
4, UNIT_END01,
5, UNIT_END02
) AS "EnduranceRoll")))
FROM (SELECT mcah.END01, mcah.UNIT_END01, mcah.END02,
mcah.UNIT_END02,
mcpd.Sub, mcpd.Cat, mcpd.Main
mcpd.END01 as "Value01", mcpd.END02 as "Value02"
FROM enduranceDiv mcah, enduranceMain mcpd
WHERE mcpd.sub = mcah.sub
AND mcpd.cat = mcah.cat
),
(SELECT 1 q, 1 r, 1 s
FROM DUAL
UNION ALL
SELECT 2, 2, 2
FROM DUAL
UNION ALL
SELECT 3, 3, 3
FROM DUAL
UNION ALL
SELECT 4, 4, 4
FROM DUAL
UNION ALL
SELECT 5, 5, 5
FROM DUAL) WHERE main = p.main ---> AND
"EnduranceName" IS NOT NULL <---
)
)))
from enduranceMain p where p.main = 'Product1' )
)
from dual

The problem is when I have null values for the 5 values in the decode function
I'll be left with a <Endurance />
Which I don't want - that's why I want to write something similar to what I've
added to the where clause (EnduranceName is not null). When EnduranceName is
null then all the other values are also null for sure.

Do you have some simple way in mind of easily resolve this?

Brgds,

/Tony



Tom Kyte
March 04, 2005 - 10:16 am UTC

I asked Sean Dillon, our local XML guy, to take a look at this, here's what he had to say:
--

Tony,

I'm a little confused with what you're trying to do, but there are a couple of bits of advice I can offer.

1. If you want to force an element to be in the result set of an SQLXML query, whether it has a value or not, use XMLELEMENT as your query operator. If the result value for that column is null, you'll get a self-closed tag in your result (i.e., <NULLCOLUMN/>).

2. If you want to only show an element if it has a value, use the XMLFOREST SQLXML query operator. This will remove elements from the resulting document if the result value for that column is null.

3. If you want to selectively query columns in your query based on the value of EnduranceName (or some condition), use a plain ole CASE statement. You can embed the other nodes you want queried inside the case statement's based on satisfying some condition, or alternatively choose to select no subnodes if the condition isn't met (etc..).



How to generate XML files in client side(FORM 10g)

AS, May 16, 2005 - 5:36 pm UTC

Hi,

DB: 9iR2, form ORACLE 10g
1. Would you mind give me an example on how to write XML files on client side (and store them there), not server side;

2. Related to question 1, we want to generate data files in EXCEL format in 10g form on client side, but don't want your SLK file format anymore. So we want to first generate the data file in XML format, and then try to open it by Office 2003, is it a good way and how to do that if it is?

3. Do you have any inputs on that issue please?

Thanks for your time.


Tom Kyte
May 16, 2005 - 5:56 pm UTC

1) retrieve xml from database into client application written in language of your choice and write to file system...

2) it is not "my" sylk file format, it is the industries....

but you would do precisely the same thing you would for sylk. if you want to do this on the client, write code on client in language of choice

3) the more you centralize and the less you clientize the better you'll be in the long run...

Deleting from a table of xmltype

Claude, January 16, 2006 - 4:49 pm UTC

Hi Tom/Sean,
I have hopefully a simple question for you that I can't figure out...

I'm creating a simple xmltype table with no key. The commands that I use to create and populate it are shown. Later I want to delete a row based on a key.

create table items of xmltype;

insert into items
values (xmltype.createxml(
'<item>'||
'<id>123</id>'||
'<name>smooth paper</name>'||
'</item>'));

insert into items
values (xmltype.createxml(
'<item>'||
'<id>456</id>'||
'<name>noisy printer</name>'||
'</item>'));

commit;

Now I want to delete the record with the ID of 123. How do I do that? ie...

delete from items i
where extract(value(i), '/items/id') = '123'
/
but without the ORA-22950 error.

Thanks



XML Version tag revisited

Reed Hammond, February 09, 2006 - 1:42 pm UTC

Hi Tom,

I am trying to add the <?xml version="1.0"?> tag to the beginning of my xml output. I noticed a followup on this thread that gave me something to try so I added

mltype.createxml('<?xml version="1.0"?>' ||

to a query I had working, right after the select with a close parenthesis before the from statement, but now I am getting the error ORA-19011: Character string buffer too small.

I was expecting the output to generate in a clob.Is the database converting the output to something other than a clob before it returns? Is there something else I should be doing?

Thanks

Tom Kyte
February 10, 2006 - 11:30 am UTC

if you concatenated a string to a string, you get a string...

you might have to convert to let it know what you mean:

ops$tkyte@ORA10GR2> create table t ( x clob );
 
Table created.
 
ops$tkyte@ORA10GR2>
ops$tkyte@ORA10GR2> declare
  2          l_str varchar2(4000) := rpad('*',4000,'*');
  3  begin
  4          insert into t values ( 'abc' || l_str );
  5  end;
  6  /
declare
*
ERROR at line 1:
ORA-01489: result of string concatenation is too long
ORA-06512: at line 4
 
 
ops$tkyte@ORA10GR2> declare
  2          l_str varchar2(4000) := rpad('*',4000,'*');
  3  begin
  4          insert into t values ( 'abc' || to_clob(l_str) );
  5  end;
  6  /
 
PL/SQL procedure successfully completed.
 

Using xmlschema as object relational

Claude, March 02, 2006 - 3:44 pm UTC

Hi Tom,
I tried to create a table with schema-based storage but didn't get very far.

SQL> CREATE TABLE students(student_id VARCHAR2(15) NOT NULL,
                        student_xml XMLType NOT NULL)
XMLTYPE COLUMN student_xml STORE AS OBJECT RELATIONAL
XMLSCHEMA "students.xsd"
ELEMENT "student";

CREATE TABLE students (student_id  VARCHAR2(15)  NOT NULL,
*
ERROR at line 1:
ORA-00902: invalid datatype

Here is the register-schema command I'm using:

   DBMS_XMLSCHEMA.REGISTERSCHEMA(
   schemaurl => 'students.xsd',
   schemadoc => '<xsd:schema xmlns:xsd="
http://www.w3.org/2001/XMLSchema" >
      <xsd:element name="student">
         <xsd:complexType>
            <xsd:sequence>
               <xsd:element name="change_date" type="xsd:string"/>
               <xsd:element name="enrollment_term">
                  <xsd:complexType>
                     <xsd:sequence>
                        <xsd:element name="semester" type="xsd:string"/>
                        <xsd:element name="status" type="xsd:string"/>
                     </xsd:sequence>
                  </xsd:complexType>
               </xsd:element>
            </xsd:sequence>
            <xsd:attribute name="id" type="xsd:string"/>
            <xsd:attribute name="person_name" type="xsd:string"/>
            <xsd:attribute name="ssn" type="xsd:string"/>
         </xsd:complexType>
      </xsd:element>
   </xsd:schema>',
   local => TRUE,
   gentypes => TRUE,
   gentables => FALSE
);


Metalink says to use the clause "store as clob". That gets rid of the error, but loses the ability to use schema-based storage (and B*Tree indexes, etc). What am I missing?
Thanks
 

Tom Kyte
March 03, 2006 - 7:48 am UTC

ops$tkyte@ORA10GR2> CREATE TABLE students(student_id VARCHAR2(15) NOT NULL,
  2                          student_xml XMLType NOT NULL)
  3  XMLTYPE COLUMN student_xml STORE AS OBJECT RELATIONAL
  4  XMLSCHEMA "students.xsd"
  5  ELEMENT "student";
 
Table created.
 


version?

ops$tkyte@ORA10GR2> select * from v$version;
 
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE    10.2.0.1.0      Production
TNS for Linux: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production
 
 

Using xmlschema as object relational

Claude, March 03, 2006 - 9:15 am UTC

Here's the version I'm using:

BANNER
---------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.5.0 - 64bit Production
PL/SQL Release 9.2.0.5.0 - Production
CORE 9.2.0.6.0 Production
TNS for Solaris: Version 9.2.0.5.0 - Production
NLSRTL Version 9.2.0.5.0 - Production


Tom Kyte
March 03, 2006 - 12:56 pm UTC

seems more like something is wrong with your installation perhaps, please work with support:

ops$tkyte@ORA9IR2> begin
  2     DBMS_XMLSCHEMA.REGISTERSCHEMA(
  3     schemaurl => 'students.xsd',
  4     schemadoc => '<xsd:schema xmlns:xsd="
http://www.w3.org/2001/XMLSchema" >
  5        <xsd:element name="student">
  6           <xsd:complexType>
  7              <xsd:sequence>
  8                 <xsd:element name="change_date" type="xsd:string"/>
  9                 <xsd:element name="enrollment_term">
 10                    <xsd:complexType>
 11                       <xsd:sequence>
 12                          <xsd:element name="semester" type="xsd:string"/>
 13                          <xsd:element name="status" type="xsd:string"/>
 14                       </xsd:sequence>
 15                    </xsd:complexType>
 16                 </xsd:element>
 17              </xsd:sequence>
 18              <xsd:attribute name="id" type="xsd:string"/>
 19              <xsd:attribute name="person_name" type="xsd:string"/>
 20              <xsd:attribute name="ssn" type="xsd:string"/>
 21           </xsd:complexType>
 22        </xsd:element>
 23     </xsd:schema>',
 24     local => TRUE,
 25     gentypes => TRUE,
 26     gentables => FALSE
 27  );
 28  end;
 29  /
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA9IR2> CREATE TABLE students(student_id VARCHAR2(15) NOT NULL,
  2                          student_xml XMLType NOT NULL)
  3  XMLTYPE COLUMN student_xml STORE AS OBJECT RELATIONAL
  4  XMLSCHEMA "students.xsd"
  5  ELEMENT "student";
 
Table created.
 
ops$tkyte@ORA9IR2> select * from v$version;
 
BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.5.0 - Production
PL/SQL Release 9.2.0.5.0 - Production
CORE    9.2.0.6.0       Production
TNS for Linux: Version 9.2.0.5.0 - Production
NLSRTL Version 9.2.0.5.0 - Production
 

Using xmlschema as object relational

Claude, March 03, 2006 - 4:49 pm UTC

That example works for me now too. The example I put together I touched up to remove the confidential information and I guess I inadvertantly fixed it in the process. :-[
This gives me something to work on for now. Thanks for your quick responses.

A reader, March 26, 2006 - 12:26 pm UTC

Hi Tom,

We have xsd:dateTime type with the foramt in the xsd. It's really giving me hard time. It is expecting value in following format 2006-02-16T11:14:26

How can I get this field value in oracle.

I tried following but it's giving me error...


XMLForest( sp_eim_key.nextval as "trans_id"
, TO_CHAR(a.last_upd,'YYYY-MM-DD"T"hh24:mi:SS') as "trans_date" <<<<<<<<<<<---------------------- ,'SADMIN' as "trans_creator"
,'MH' as "source_system"
, 'U' as "rec_type"
)
)



<xsd:element name="trans_date" nillable="false">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>
Date the record was placed in the queue/drop location.
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:dateTime">
<xsd:pattern value="\p{Nd}{4}-\p{Nd}{2}-\p{Nd}{2}T\p{Nd}{2}:\p{Nd}{2}:\p{Nd}{2}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>


P.S - I am generating the xml document using sqlx function and validating it againt the xsd. I have already registered the schema in the database.

Thanks

A reader, March 26, 2006 - 12:29 pm UTC

Forgot to mention one thing..

Just checked underlying db ojbects created by xbms_xmlschema.registerschema proocedure and found TIMESTAMP datatype created for "xsd:dateTime"


Xml Query Input

sagar, September 04, 2006 - 3:27 pm UTC

Hi Tom,
Is it possible to query the database using xml. My Sample XML Query will be some thing like

<Query>
<Select>All</Select>
<From>
<Tablename>emp</Tablename>
</From>
<WhereCondition>All</WhereCondition>
</Query>

Basically I am try to do (select * from emp);

Identical Attributes

A reader, February 08, 2007 - 9:27 am UTC

I have an XML file whcih resides on the FTP site

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cXML SYSTEM " http://xml.cXML.org/schemas/cXML/1.2.011/Fulfill.dtd" >
<cXML timestamp="2007-02-06T01:21:26+00:00" xml:lang="en-US" payloadID="1170724886050.7621197.85262388@SEAAPP11">
<Header>
<From>
<Credential domain="DUNS">
<Identity>001903202</Identity>
</Credential>
</From>
<To>
<Credential domain="ZZ">
<Identity>ADPDS</Identity>
</Credential>
</To>
<Sender>
<Credential domain="DUNS">
<Identity>001903202</Identity>
</Credential>
<UserAgent>Hubspan Translation Services</UserAgent>
</Sender>
</Header>
<Request deploymentMode="test">
<ShipNoticeRequest>
<ShipNoticeHeader shipmentID="0800018638" noticeDate="2007-02-02T12:00:00-12:00" shipmentDate="2007-02-02T12:00:00-12:00" deliveryDate="2007-02-08T12:00:00-12:00">
<Contact role="shipFrom">
<Name xml:lang="en-US">GRAYBAR ELECTRIC CO</Name>
<PostalAddress>
<Street/>
<City>MINNEAPOLIS</City>
<State>MN</State>
<PostalCode>55406</PostalCode>
<Country isoCountryCode="US"/>
</PostalAddress>
</Contact>
<Contact role="shipTo">
<Name xml:lang="en-US">GROUP 1 BOB HOWARD A</Name>
<PostalAddress>
<Street>100 NORTH WEST POINTE BLVD</Street>
<City>ELK GROVE VILLAGE</City>
<State>IL</State>
<PostalCode>60007</PostalCode>
<Country isoCountryCode="US"/>
</PostalAddress>
</Contact>
</ShipNoticeHeader>
<ShipControl>
<CarrierIdentifier domain="companyName">4M UPS - GROUND</CarrierIdentifier>
<ShipmentIdentifier>0800018638</ShipmentIdentifier>
</ShipControl>
<ShipNoticePortion>
<OrderReference orderID="1141562">
<DocumentReference payloadID=""/>
</OrderReference>
<ShipNoticeItem quantity="5" lineNumber="000101">
<UnitOfMeasure>EA</UnitOfMeasure>
</ShipNoticeItem>
</ShipNoticePortion>
</ShipNoticeRequest>
</Request>
</cXML>

here i need to get values of attributes under <Contact role="shipTo"> attribute if you look at the above file we have <COntact role="xxxx"> twice now while using

v_xml_dom_det_info_list := xpath.SelectNodes( p_xml_dom_doc, 'cXML/Request/ShipNoticeRequest/ShipNoticeHeader/Contact' );
v_contact_shipto := xpath.valueof( v_xml_dom_det_info_list,'role');

how can i make sure v_contact_shipto gets "Shipto" value only.

Thanks,

Ark

A reader, December 08, 2011 - 11:08 am UTC

Hi Tom,

I have an XML document (file name = employee.txt) with the below XML :

<Employee>
<id>1234</id>
<Name>Shane</Name>
<Sal>12345</Salary>
<dept_id>45</dept_id>
<Address_details>abcdefgh</ Address_details >
</Employee>


1.I want to extract the above data and insert into 2 tables
a.Employee table (id,Name,Sal,dept_id)
b.Address table (id,Address_details)


2.Similary I want to generate the XML in the above format from the 2 tables . How can we do that ?

Could you please advise the best way to do these on Oracle 11g R2?

Thanks

More to Explore

CLOB/BLOB/etc

Complete documentation on Securefiles and Large Objects here