Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Kristi.

Asked: October 29, 2001 - 4:21 pm UTC

Last updated: May 09, 2011 - 8:57 am UTC

Version: Oracle9i

Viewed 1000+ times

You Asked

I started with the example online at DBMS_XMLGEN Example 5:
</code> http://download-west.oracle.com/otndoc/oracle9i/901_doc/appdev.901/a88894/adx05xml.htm#1015194 <code>and modified it for my database. I am able to format all of my tags except for the top level tag. By naming the column that points to a particular Object Type I can name all my tags something like this:

<?xml version="1.0"?>
<Msg>
<FileGet>
<SYS_FIL_CASE16 PK="1001" UT="1" UserID="Bob">
<Col CaseNo="A245" ShortTitle="Test Case"/>
<Ent PK="501" UT="1" PKParent="1001" ParentEntCode="CAS" PKFile="1001" UserID="1">
<Col Ref_PartyType_ID="1" FirstName="Bob" MiddleName="T" LastName="Jones"/>
<Ent PK="2" UT="1" PKParent="501" ParentEntCode="1" PKFile="1001" UserID="1">
<Col Ref_AddressType_ID="1" Address1="124 Main Street" Address2="Apt. B" City="Denver"/>
</Ent>
</Ent>
</SYS_FIL_CASE16>
</FileGet>
</Msg>


Since the top level tag, SYS_FIL_CASE16, is actually a TYPE that is a TABLE consisting of all other types making up the hierarchical set of tables/data. I seem to be stuck with the tag SYS_FIL_CASE16 and can't seem to get around it because its not a column, its a type. Is there any way to get around this so I can name it Ent??

Since all of my xml will need to be formatted this way, I will have multiple types named the same which of course is not possible to do. Is there a way to not use the create type x as table of y and just create the hierarchical types as columns of the other tables?? I tried this with the example 5 and the CAST fails. I am thinking since I was able to name all the other tags, I have to be able to name this last one.???

-----------------------------------------------------------
Additional Info: I would like to get this out of sql and not transform it.
------------------------------------------------------------

-- Table ddl pulled from oem
CREATE TABLE "KRISTI"."ENT_ADDRESS" ("PK" VARCHAR2(38 byte) NOT
NULL, "UT" VARCHAR2(38 byte) NOT NULL, "PKPARENT"
VARCHAR2(38 byte) NOT NULL, "PARENTENTCODE" VARCHAR2(3 byte)
NOT NULL, "PKFILE" VARCHAR2(38 byte), "USERID" VARCHAR2(38
byte) NOT NULL, "REF_ADDRESSTYPE_ID" NUMBER(38) NOT NULL, "ADDRESS1"
VARCHAR2(60 byte) NOT NULL, "ADDRESS2" VARCHAR2(60 byte), "ADDRESS3"
VARCHAR2(60 byte), "ADDRESS4" VARCHAR2(60 byte), "CITY"
VARCHAR2(30 byte) NOT NULL, "REF_STATEPROVINCE_ID"
NUMBER(38) NOT NULL, "ZIPPOSTALCODE" VARCHAR2(10 byte),
CONSTRAINT "PK_ENT_ADDRESS" PRIMARY KEY("PK")
USING INDEX
TABLESPACE "INDX"
STORAGE ( INITIAL 64K NEXT 0K MINEXTENTS 1 MAXEXTENTS
2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1)
PCTFREE 10 INITRANS 2 MAXTRANS 255)
TABLESPACE "USERS" PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS
255
STORAGE ( INITIAL 64K NEXT 0K MINEXTENTS 1 MAXEXTENTS
2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1)
LOGGING;

CREATE TABLE "KRISTI"."ENT_PARTY" ("PK" VARCHAR2(38 byte) NOT
NULL, "UT" VARCHAR2(38 byte) NOT NULL, "PKPARENT"
VARCHAR2(38 byte) NOT NULL, "PARENTENTCODE" VARCHAR2(3 byte)
NOT NULL, "PKFILE" VARCHAR2(38 byte), "USERID" VARCHAR2(38
byte) NOT NULL, "REF_PARTYTYPE_ID" NUMBER(38) NOT NULL, "FIRSTNAME"
VARCHAR2(30 byte) NOT NULL, "MIDDLENAME" VARCHAR2(30 byte), "LASTNAME"
VARCHAR2(30 byte) NOT NULL,
CONSTRAINT "PK_ENT_PARTY" PRIMARY KEY("PK")
USING INDEX
TABLESPACE "INDX"
STORAGE ( INITIAL 64K NEXT 0K MINEXTENTS 1 MAXEXTENTS
2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1)
PCTFREE 10 INITRANS 2 MAXTRANS 255)
TABLESPACE "USERS" PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS
255
STORAGE ( INITIAL 64K NEXT 0K MINEXTENTS 1 MAXEXTENTS
2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1)
LOGGING ;

CREATE TABLE "KRISTI"."FIL_CASE" ("PK" VARCHAR2(38 byte) NOT NULL,
"UT" VARCHAR2(38 byte) NOT NULL, "USERID" VARCHAR2(38 byte)
NOT NULL, "CASENO" VARCHAR2(10 byte) NOT NULL, "SHORTTITLE"
VARCHAR2(30 byte) NOT NULL, "REF_CASETYPE_ID" NUMBER(38) NOT
NULL, "REF_DISPOSITIONTYPE_ID" NUMBER(38), "REF_DISPOSITIONSTAGE_ID"
NUMBER(38), "FILINGDATE" DATE NOT NULL, "DISPDATE" DATE, "REF_OFFICIAL_ID"
NUMBER(38), "CAS_OFF_FIRSTNAME" VARCHAR2(10 byte), "CAS_OFF_LASTNAME"
VARCHAR2(20 byte),
CONSTRAINT "PK_FIL_CASE" PRIMARY KEY("PK")
USING INDEX
TABLESPACE "INDX"
STORAGE ( INITIAL 64K NEXT 0K MINEXTENTS 1 MAXEXTENTS
2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1)
PCTFREE 10 INITRANS 2 MAXTRANS 255)
TABLESPACE "USERS" PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS
255
STORAGE ( INITIAL 64K NEXT 0K MINEXTENTS 1 MAXEXTENTS
2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1)
LOGGING ;

CREATE TABLE temp_clob_tab(result CLOB);

create table sxmsg(pk varchar(38));

-- inserts
insert into sxmsg(pk) values(1001);
INSERT INTO "KRISTI"."FIL_CASE" ("PK" ,"UT" ,"USERID" ,"CASENO" ,"SHORTTITLE" ,"REF_CASETYPE_ID" ,"REF_DISPOSITIONTYPE_ID" ,"REF_DISPOSITIONSTAGE_ID" ,"FILINGDATE" ,"DISPDATE" ,"REF_OFFICIAL_ID" ,"CAS_OFF_FIRSTNAME" ,"CAS_OFF_LASTNAME" )
VALUES ('1001' ,'1' ,'Bob' ,'A245' ,'Test Case' ,1 ,1 ,1 ,sysdate ,sysdate ,1 ,'George' ,'Smith' );
INSERT INTO "KRISTI"."ENT_PARTY" ("PK" ,"UT" ,"PKPARENT" ,"PARENTENTCODE" ,"PKFILE" ,"USERID" ,"REF_PARTYTYPE_ID" ,"FIRSTNAME" ,"MIDDLENAME" ,"LASTNAME" )
VALUES ('501' ,'1' ,'1001' ,'CAS' ,'1001' ,'1' ,1 ,'Bob' ,'T' ,'Jones' )
INSERT INTO "KRISTI"."ENT_ADDRESS" ("PK" ,"UT" ,"PKPARENT" ,"PARENTENTCODE" ,"PKFILE" ,"USERID" ,"REF_ADDRESSTYPE_ID" ,"ADDRESS1" ,"ADDRESS2" ,"ADDRESS3" ,"ADDRESS4" ,"CITY" ,"REF_STATEPROVINCE_ID" ,"ZIPPOSTALCODE" )
VALUES ('2' ,'1' ,'501' ,'1' ,'1001' ,'1' ,1 ,'124 Main Street' ,'Apt. B' ,'' ,'' ,'Denver' ,3 ,'80201' )

-- types
CREATE or REPLACE TYPE ent_address16 AS OBJECT(
"@Ref_AddressType_ID" NUMBER(38),
"@Address1" VARCHAR2(30),
"@Address2" VARCHAR2(30),
"@Address3" VARCHAR2(30),
"@Address4" VARCHAR2(30),
"@City" varchar2(30),
"@Ref_StateProvince_ID" number(38),
"@ZipPostalCode" VARCHAR2(10)
);
/

CREATE OR REPLACE TYPE sys_ent_address16 AS OBJECT(
"@PK" VARCHAR2(38),
"@UT" VARCHAR2(38),
"@PKParent" VARCHAR2(38),
"@ParentEntCode" VARCHAR2(3),
"@PKFile" VARCHAR2(38),
"@UserID" VARCHAR2(38),
"Col" ent_address16
);
/

CREATE OR REPLACE TYPE ent_party16 AS OBJECT(
"@Ref_PartyType_ID" varchar2(38),
"@FirstName" VARCHAR2(30),
"@MiddleName" varchar2(30),
"@LastName" varchar2(38)
);
/

CREATE OR REPLACE TYPE sys_ent_party16 AS OBJECT(
"@PK" VARCHAR2(38),
"@UT" VARCHAR2(38),
"@PKParent" VARCHAR2(38),
"@ParentEntCode" VARCHAR2(3),
"@PKFile" VARCHAR2(38),
"@UserID" VARCHAR2(38),
"Col" ent_party16,
"Ent" sys_ent_address16
);
/

CREATE OR REPLACE TYPE fil_case16 AS OBJECT(
"@CaseNo" varchar2(10),
"@ShortTitle" VARCHAR2(30),
"@Ref_CaseType_ID" Number(38),
"@Ref_DispositionType_ID" Number(38),
"@FilingDate" Date,
"@DispDate" Date
);
/

CREATE OR REPLACE TYPE sys_fil_case16 AS OBJECT(
"@PK" VARCHAR2(38),
"@UT" VARCHAR2(38),
"@UserID" varchar2(10),
"Col" fil_case16,
"Ent" sys_ent_party16
);
/

CREATE OR REPLACE TYPE CasePartyAddress16_ntabtyp AS TABLE OF sys_fil_case16
/

CREATE OR REPLACE TYPE sxmsg16 AS OBJECT(
pk VARCHAR2(38),
CasePartyAddr CasePartyAddress16_ntabtyp
);
/

-- view
CREATE OR REPLACE VIEW CasePartyAddress OF sxmsg16
WITH OBJECT IDENTIFIER (PK)
AS SELECT s.pk,
CAST( MULTISET(
SELECT sys_fil_case16(sc.pk, sc.ut, sc.userid,
fil_case16(c.caseno, c.shorttitle, c.ref_casetype_id, c.ref_dispositiontype_id, c.filingdate, c.dispdate),
sys_ent_party16(sp.PK, sp.UT, sp.PKParent, sp.parentEntCode, sp.pkfile, sp.userid,
ent_party16(p.Ref_PartyType_ID, p.FirstName, p.MiddleName, p.LastName),
sys_ent_address16(sa.PK, sa.UT, sa.PKParent, sa.parentEntCode, sa.pkfile, sa.userid,
ent_address16(a.ref_addresstype_id, a.address1, a.address2, a.address3, a.address4, a.city, a.ref_stateprovince_id, a.zippostalcode))))
FROM fil_case sc, fil_case c, ent_party sp, ent_party p, ent_address sa, ent_address a
WHERE sc.pk = s.pk and sc.pk = c.pk and sp.pkparent = c.pk and sp.pk = p.pk and sa.pkparent = p.pk and sa.pk = a.pk )
AS CasePartyAddress16_ntabtyp)
FROM sxmsg s;

-- procedure
CREATE OR REPLACE PROCEDURE "KRISTI"."SP_DBMS_XMLGEN"
AS
qryCtx DBMS_XMLGEN.ctxHandle;
result CLOB;
BEGIN
qryCtx := dbms_xmlgen.newContext('
SELECT CasePartyAddr "FileGet"
FROM CasePartyAddress d'
);
DBMS_XMLGEN.setRowTag(qryCtx, NULL);
DBMS_XMLGEN.setRowSetTag(qryCtx, 'Msg');
DELETE temp_clob_tab;
result := DBMS_XMLGEN.getXML(qryCtx);
INSERT INTO temp_clob_tab VALUES(result);
End;
/

-- sqlplus
set serveroutput on;
begin
sp_dbms_xmlgen();
end;
/
set pagesize 2000;
set linesize 120;
set long 4000;
select * from temp_clob_tab;

and Tom said...

I sent this to our resident XML guru, Sean Dillon and he says....

It's relatively easy to change the names of elements in generated XML from DBMS_XMLGEN. You can use column aliases to accomplish this. In the following example, I build a couple of simple types and then use two different queries in the DBMS_XMLGEN.NEWCONTEXT call to modify the element names of my generated xml documents:

SQL> create type phonelist_vartyp as varray(10) of varchar2(20)
2 /

Type created.

SQL> create type address_typ as object(
2 street varchar2(200),
3 city varchar2(200),
4 state char(2),
5 zip varchar2(20)
6 )
7 /

Type created.

SQL> create type customer_typ as object(
2 customer_no number,
3 customer_name varchar2(200),
4 address address_typ,
5 phone_list phonelist_vartyp
6 )
7 /

Type created.

SQL> create table customer_tab(
2 customer_no number,
3 customer_name varchar2(200),
4 street varchar2(200),
5 city varchar2(200),
6 state char(2),
7 zip varchar2(20),
8 phone1 varchar2(20),
9 phone2 varchar2(20),
10 phone3 varchar2(20),
11 phone4 varchar2(20),
12 constraint customer_pk primary key (customer_no)
13 )
14 /

Table created.

SQL> create or replace view customer_view
2 of customer_typ
3 with object identifier( customer_no )
4 as select ct.customer_no, ct.customer_name,
5 address_typ( ct.street, ct.city, ct.state, ct.zip ),
6 phonelist_vartyp( ct.phone1, ct.phone2, ct.phone3, ct.phone4 )
7 from customer_tab ct
8 /

View created.

SQL> insert into customer_tab values (1, 'Jean Nance', '2 Avocet Drive',
2 'Redwood Shores', 'CA', '95054',
3 '415-555-1212', '650-123-3456', '609-555-1212', '201-555-1212') ;

1 row created.

SQL> insert into customer_tab values (2, 'John Nike', '323 College Drive',
2 'Edison', 'NJ', '08820',
3 '609-555-1212', '201-555-1212', '415-555-1212', '650-123-3456') ;

1 row created.

SQL> set autoprint on
SQL> variable c clob;
SQL> declare
2 qryctx dbms_xmlgen.ctxhandle;
3 begin
4 -- notice SELECT *: just take the defaults
5 qryctx := dbms_xmlgen.newcontext('select * from customer_view');
6 dbms_xmlgen.setrowsettag(qryctx,'PeopleList');
7 dbms_xmlgen.setrowtag(qryctx,'Employees');
8 :c := dbms_xmlgen.getxml(qryctx);
9 end;
10 /

PL/SQL procedure successfully completed.

C
-------------------------------------------------------------------------------
<?xml version="1.0"?>
<PeopleList>
<Employees>
<CUSTOMER_NO>1</CUSTOMER_NO>
<CUSTOMER_NAME>Jean Nance</CUSTOMER_NAME>
<ADDRESS>
<STREET>2 Avocet Drive</STREET>
<CITY>Redwood Shores</CITY>
<STATE>CA</STATE>
<ZIP>95054</ZIP>
</ADDRESS>
<PHONE_LIST>
<VARCHAR2>415-555-1212</VARCHAR2>
<VARCHAR2>650-123-3456</VARCHAR2>
<VARCHAR2>609-555-1212</VARCHAR2>
<VARCHAR2>201-555-1212</VARCHAR2>
</PHONE_LIST>
</Employees>
<Employees>
<CUSTOMER_NO>2</CUSTOMER_NO>
<CUSTOMER_NAME>John Nike</CUSTOMER_NAME>
<ADDRESS>
<STREET>323 College Drive</STREET>
<CITY>Edison</CITY>
<STATE>NJ</STATE>
<ZIP>08820</ZIP>
</ADDRESS>
<PHONE_LIST>
<VARCHAR2>609-555-1212</VARCHAR2>
<VARCHAR2>201-555-1212</VARCHAR2>
<VARCHAR2>415-555-1212</VARCHAR2>
<VARCHAR2>650-123-3456</VARCHAR2>
</PHONE_LIST>
</Employees>
</PeopleList>


SQL> declare
2 qryctx dbms_xmlgen.ctxhandle;
3 begin
4 -- in this one, we use aliases to make attributes and rename elements:
5 qryctx := dbms_xmlgen.newcontext('
6 select customer_no "@cno", customer_name "@cname",
7 address "address_info", phone_list "phone_numbers"
8 from customer_view');
9 dbms_xmlgen.setrowsettag(qryctx,'PeopleList');
10 dbms_xmlgen.setrowtag(qryctx,'Employees');
11 :c := dbms_xmlgen.getxml(qryctx);
12 end;
13 /

PL/SQL procedure successfully completed.

C
-------------------------------------------------------------------------------
<?xml version="1.0"?>
<PeopleList>
<Employees cno="1" cname="Jean Nance">
<address_info>
<STREET>2 Avocet Drive</STREET>
<CITY>Redwood Shores</CITY>
<STATE>CA</STATE>
<ZIP>95054</ZIP>
</address_info>
<phone_numbers>
<VARCHAR2>415-555-1212</VARCHAR2>
<VARCHAR2>650-123-3456</VARCHAR2>
<VARCHAR2>609-555-1212</VARCHAR2>
<VARCHAR2>201-555-1212</VARCHAR2>
</phone_numbers>
</Employees>
<Employees cno="2" cname="John Nike">
<address_info>
<STREET>323 College Drive</STREET>
<CITY>Edison</CITY>
<STATE>NJ</STATE>
<ZIP>08820</ZIP>
</address_info>
<phone_numbers>
<VARCHAR2>609-555-1212</VARCHAR2>
<VARCHAR2>201-555-1212</VARCHAR2>
<VARCHAR2>415-555-1212</VARCHAR2>
<VARCHAR2>650-123-3456</VARCHAR2>
</phone_numbers>
</Employees>
</PeopleList>

That's it... you have pretty good control over your generated XML element names, as well as the flexibility to move elements to attributes by aliasing columns with at-signs (from the block above):

6 select customer_no "@cno", customer_name "@cname",

...resulted in:

<Employees cno="1" cname="Jean Nance">
...and...
<Employees cno="2" cname="John Nike">

If you are constructing a type in your query, you can alias that as well. The following block would work fine:

SQL> declare
2 qryctx dbms_xmlgen.ctxhandle;
3 begin
4 qryctx := dbms_xmlgen.newcontext('
5 select ct.customer_no, ct.customer_name,
6 address_typ(ct.street, ct.city, ct.state, ct.zip) "addresses",
7 phonelist_vartyp(ct.phone1, ct.phone2, ct.phone3, ct.phone4) "phone_numbers"
8 from customer_tab ct');
9 dbms_xmlgen.setrowsettag(qryctx,'PeopleList');
10 dbms_xmlgen.setrowtag(qryctx,'Employees');
11 :c := dbms_xmlgen.getxml(qryctx);
12 end;
13 /

You get the idea... hope that helps!

***********************************************************
FOLLOW-UP TO REVIEW 1:
Yeah, using cast(multiset in your view makes the standard column aliasing functionality a bit more difficult. You could easily use XSLT to transform the resulting document to whatever it is you want the new entity names to be, for example:

SQL> create or replace function transform_xml_with_xsl(
2 p_xml in clob,
3 p_xsl in clob )
4 return clob
5 is
6 l_par xmlparser.parser;
7 l_xml xmldom.domdocument;
8 l_pro xslprocessor.processor;
9 l_xsl xslprocessor.stylesheet;
10 l_clob clob;
11 begin
12 l_par := xmlparser.newparser;
13 xmlparser.parseclob(l_par, p_xsl);
14 l_xsl := xslprocessor.newstylesheet(xmlparser.getdocument(l_par),null);
15 xmlparser.parseclob(l_par, p_xml);
16 l_xml := xmlparser.getdocument(l_par);
17 dbms_lob.createtemporary(l_clob, true, dbms_lob.session);
18 l_pro := xslprocessor.newprocessor;
19 xslprocessor.processxsl(l_pro,l_xsl,l_xml,l_clob);
20 xmlparser.freeparser(l_par);
21 xslprocessor.freeprocessor(l_pro);
22 return l_clob;
23 exception
24 when others then
25 xmlparser.freeparser(l_par);
26 xslprocessor.freeprocessor(l_pro);
27 raise;
28 end transform_xml_with_xsl;
29 /

Function created.

SQL> create or replace function sp_dbms_xmlgen
2 return clob
3 as
4 l_qryctx dbms_xmlgen.ctxhandle;
5 l_xsl clob;
6 begin
7 l_xsl :=
8 '<?xml version="1.0"?>
9 <xsl:stylesheet xmlns:xsl="</code> http://www.w3.org/1999/XSL/Transform" <code>version="1.0">
10 <xsl:template match="node()|@*">
11 <xsl:copy>
12 <xsl:apply-templates select="@*|node()"/>
13 </xsl:copy>
14 </xsl:template>
15
16 <xsl:template match="SYS_FIL_CASE16">
17 <NEWENT><xsl:apply-templates select="@*|node()"/></NEWENT>
18 </xsl:template>
19 </xsl:stylesheet>';
20
21 l_qryctx := dbms_xmlgen.newcontext('
22 select casepartyaddr "FileGet"
23 from casepartyaddress d');
24 dbms_xmlgen.setrowtag(l_qryctx, null);
25 dbms_xmlgen.setrowsettag(l_qryctx, 'msg');
26
27 return transform_xml_with_xsl(
28 p_xml => dbms_xmlgen.getxml(l_qryctx),
29 p_xsl => l_xsl );
30
31 end;
32 /

Function created.

SQL> show errors
No errors.
SQL>
SQL> var c clob;
SQL> begin
2 :c := sp_dbms_xmlgen;
3 end;
4 /

PL/SQL procedure successfully completed.


C
-------------------------------------------------------------------------------
<?xml version = '1.0' encoding = 'UTF-8'?>
<msg>
<FileGet>
<NEWENT PK="1001" UT="1" UserID="Bob">
<Col CaseNo="A245" ShortTitle="Test Case" Ref_CaseType_ID="1"
Ref_DispositionType_ID="1" FilingDate="31-OCT-01"
DispDate="31-OCT-01"/>
<Ent PK="501" UT="1" PKParent="1001" ParentEntCode="CAS"
PKFile="1001" UserID="1">
<Col Ref_PartyType_ID="1" FirstName="Bob" MiddleName="T"
LastName="Jones"/>
<Ent PK="2" UT="1" PKParent="501" ParentEntCode="1"
PKFile="1001" UserID="1">
<Col Ref_AddressType_ID="1" Address1="124 Main Street"
Address2="Apt. B" City="Denver" Ref_StateProvince_ID="3"
ZipPostalCode="80201"/>
</Ent>
</Ent>
</NEWENT>
</FileGet>
</msg>

r/s,
Sean Dillon

Rating

  (37 ratings)

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

Comments

More complex use of Object Types

Kristi Richardson, October 30, 2001 - 3:58 pm UTC

The problem was with the top level object type.. Notice that all the columns have an alias but the top level type obviously does not.. How do you either avoid using the type so you can use an alias, OR format that tag in the example?

My unsolicited feedback

Mark A. Williams, October 30, 2001 - 11:59 pm UTC

By changing your procedure to this:

CREATE OR REPLACE PROCEDURE kristi.sp_dbms_xmlgen AS
  qryctx dbms_xmlgen.ctxhandle;
  result clob;
BEGIN
  qryctx := dbms_xmlgen.newcontext('
  select casepartyaddr "FileGet" from casepartyaddress');
  dbms_xmlgen.setrowtag(qryctx, NULL);
  dbms_xmlgen.setrowsettag(qryctx, 'Msg');
  dbms_xmlgen.useitemtagsforcoll(qryctx);
  delete from temp_clob_tab;
  commit;
  result := dbms_xmlgen.getxml(qryctx);
  insert into temp_clob_tab values (result);
  commit;
  dbms_xmlgen.closecontext(qryctx);
END;

You should get this as output:

SQL> begin
  2  sp_dbms_xmlgen();
  3  end;
  4  /

PL/SQL procedure successfully completed.

SQL> select * from temp_clob_tab;

RESULT
------------------------------------------------------------------
<?xml version="1.0"?>
<Msg>
 <FileGet>
  <FileGet_ITEM PK="1001" UT="1" UserID="Bob">
   <Col CaseNo="A245" ShortTitle="Test Case" Ref_CaseType_ID="1" Ref_DispositionType_ID="1" FilingDate="30-OCT-01" DispDate="30-OCT-01"/>
   <Ent PK="501" UT="1" PKParent="1001" ParentEntCode="CAS" PKFile="1001" UserID="1">
    <Col Ref_PartyType_ID="1" FirstName="Bob" MiddleName="T" LastName="Jones"/>
    <Ent PK="2" UT="1" PKParent="501" ParentEntCode="1" PKFile="1001" UserID="1">
     <Col Ref_AddressType_ID="1" Address1="124 Main Street" Address2="Apt. B" City="Denver" Ref_StateProvince_ID="3" ZipPostalCode="80201"/>
    </Ent>
   </Ent>
  </FileGet_ITEM>
 </FileGet>
</Msg>

Not 100% what you were wanting, I think, but it may help...

- Mark 

Thanks a bunch that was exactly what I needed!

Kristi Richardson, October 31, 2001 - 9:42 am UTC


the function TRANSFORM_XML_WITH_XSL does not compile..

Kristi Richardson, October 31, 2001 - 3:56 pm UTC

The function you wrote required me to grant some permissions for xmlparser, xmldom, and xslprocessor. However, when I compile the function, I am still getting an error on line 8 l_pro xslprocessor.processor....

Errors for FUNCTION TRANSFORM_XML_WITH_XSL:

LINE/COL ERROR
-------- ----------------------------------------------
8/10 PLS-00201: identifier 'XMLPROCESSOR.PROCESSOR' must be declared
8/10 PL/SQL: Item ignored
18/6 PLS-00320: the declaration of the type of this expression is incomplete or malformed

I looked in the package sys.xmlprocessor and there is no processor in there.. Am I missing something?


Tom Kyte
October 31, 2001 - 4:31 pm UTC

You need to download the latest copies of the Oracle XDKs. You can get them from Oracle Technet at </code> http://technet.oracle.com <code>They are backwards compatible, so the v9.0.1 of the XDK will work with Oracle v8.1.6. You will also need to load the Java XDK into the database as well, the PL/SQL XDKs are dependent on them.

DTD Problem

Bharath, November 21, 2002 - 5:55 pm UTC

How to avoid DOCTYPE beign generated in DTD using getxmlmetadata.Reson is when i validate generated DTD against xmlspy it's giving an error like DOCTYPE expected.Here is my code

import java.math.*;
import java.net.URL;
import java.sql.*;
import oracle.jdbc.*;
import oracle.jdbc.driver.*;
import oracle.xml.parser.v2.*;
import oracle.xml.sql.query.*;
import java.io.*;
public class GenXMl
{
public GenXMl()
{

}

public static void main(String args[]) throws SQLException,IOException
{
String tabName = "USER_TBL";
String user = "comps/comps";
URL stylesheetURL = null;
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
System.out.println("select A.deal_id as \"@deal_id \" ,");
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@ds101.dev.global.chase.com:1521:gib_dev7","comps","comps");
OracleXMLQuery qry = new OracleXMLQuery(conn,"select A.deal_id as \"@id\" ,"+
"A.name,tr_industry_desc," +
"cmb_deal JPM_lead_deal, "+
"deal_source.DEAL_SIZE_AMT_USDE ," +
"cursor( SELECT TR_PURPOSE.DESCRIPTION Purpose_Desc"+
" FROM DEAL_PROD_TYP, "+
"TR_PURPOSE "+
"WHERE ( DEAL_PROD_TYP.PRODTYP_ID = TR_PURPOSE.PRODTYP_ID ) and "+
"(deal_prod_typ.deal_id = A.deal_id ) and "+
"( ( DEAL_PROD_TYP.DATA_SOURCE_ID = 13 ) )) Purpose_details,"+
"cursor( SELECT TR_AGENT.AGENT_NAME "+
" FROM TR_DEAL_AGENT, "+
"TR_AGENT, "+
"DEAL, "+
"TR_DEAL_SOURCE "+
"WHERE ( TR_AGENT.AGENT_ID = TR_DEAL_AGENT.AGENT_ID ) and "+
"( TR_DEAL_SOURCE.DEAL_ID = DEAL.DEAL_ID ) and "+
"( TR_DEAL_SOURCE.TR_ID = TR_DEAL_AGENT.TR_ID ) and "+
"( tr_deal_source.deal_id = A.deal_id) and " +
"( ( TR_DEAL_AGENT.AGENT_TYPE_ID = 2 ))) Admin_agents ,"+
"cursor( SELECT FAC_TYPS.DESCRIPTION Facs_Desc, "+
"FACS.FAC_SIZE_AMT,"+
"GBIS.CURRENCY.DESCRIPTION Currency_desc, " +
"undrawn_txt undrawn_bps ,"+
"first_drawn_txt first_drawn_bps ,"+
"fully_drawn_txt AIS,"+
"Months_between(Trunc(Sysdate) , ADD_MONTHS(IN_MARKET_FROM_DT + " +
"DECODE(TENOR_D,NULL,0,TENOR_D), "+
"DECODE(TENOR_M,NULL,0,TENOR_M) + DECODE(TENOR_Y,NULL,0,TENOR_Y * 12))) Maturity, " +
"ADD_MONTHS(IN_MARKET_FROM_DT + " +
"DECODE(TENOR_D,NULL,0,TENOR_D), "+
"DECODE(TENOR_M,NULL,0,TENOR_M) + DECODE(TENOR_Y,NULL,0,TENOR_Y * 12)) Actual " +
" FROM DEAL, "+
" TR_DEAL_SOURCE, " +
" FACS, " +
" FAC_TYPS, "+
" GBIS.CURRENCY " +
" WHERE ( DEAL.DEAL_ID = TR_DEAL_SOURCE.DEAL_ID ) and "+
" ( TR_DEAL_SOURCE.DEAL_ID = FACS.DEAL_ID ) and "+
" ( FAC_TYPS.FAC_TYP_ID = FACS.FAC_TYP_ID ) and "+
" (A.deal_id = deal.deal_id) and "+
" ( FACS.CURRENCY_ID = GBIS.CURRENCY.ID )) as Tranche_Details ,"+
"cursor( SELECT RTNGS.DEBT_INST_ABBR, "+
" RTNG_VALS.VALUE "+
"FROM RTNGS, "+
" RTNG_VALS "+
" WHERE ( RTNG_VALS.ID = RTNGS.RTNG_VALS_ID ) and "+
"( ( RTNGS.DEAL_ID = A.deal_id ) )) AS Rating_Details , "+
"cursor( SELECT "+
"TR_DEAL_SOURCE.GROSS_UW_TXT, "+
"TR_DEAL_SOURCE.ARRANGE_FEE_TXT, "+
"TR_DEAL_SOURCE.ADMIN_FEE_TXT, "+
"TR_DEAL_SOURCE.ARRANGE_FEE_USDE "+
"FROM DEAL_SOURCE, "+
"TR_DEAL_SOURCE "+
"WHERE ( DEAL_SOURCE.DEAL_ID = TR_DEAL_SOURCE.DEAL_ID ) and "+
"( DEAL_SOURCE.DATA_SOURCE_ID = TR_DEAL_SOURCE.DATA_SOURCE_ID ) and "+
"( ( TR_DEAL_SOURCE.DEAL_ID = A.DEAL_ID ) )) AS Fee_Details " +
"FROM deal A,tr_deal_source,deal_source,tr_industry" +
" WHERE tr_deal_source.deal_id = A.deal_id" +
" and tr_deal_source.deal_id = deal_source.deal_id " +
" and tr_industry.tr_industry_id = tr_deal_source.tr_industry_id " +
" and deal_source.data_source_id = 13 and" +
" rownum < 2");
qry.setRowsetTag("DEAL_INFORMATION");//tags encapsulating the whole doc
qry.setRowTag("DEAL"); // sets the row separator tag
qry.setRowIdAttrName("");
qry.setRowIdAttrValue("");
qry.useUpperCaseTagNames(); // use upper case tag names
qry.keepObjectOpen(true);
writeTo(qry.getXMLString(),"deals.xml");
writeTo(qry.getXMLMetaData(qry.DTD,false),"deals.dtd");
qry.getXMLMetaData();
conn.close();
qry.close();
// Get the schema
// qry.setMaxRows(2); // set the maximum number of rows to be returned
// qry.setSkipRows(3); // numbers of rows to skipped
// qry.setStylesheetHeader("my.xsl"); // the stylesheet spec.

// qry.setStylesheetHeader("C:\\XML\\deals.xsl");
// XMLDocument xmldoc = (XMLDocument)qry.getXMLDOM();
// qry.setRowIdAttrName("cnt"); // sets the id attribute of the row element
// qry.useNullAttributeIndicator(true); // use attr. to indicate nullness
// qry.setErrorTag("ERR"); // tag for errors writen to XML doc
// qry.keepObjectOpen(true);
// qry.set

// String xmlMetaData = qry.getXMLMetaData(qry.DTD,true);
// print out the result to the screen
// System.out.println(" OUTPUT IS XML DATA :\n"+xmlString);
// System.out.println(" OUTPUT IS XML META DATA :\n" + xmlMetaData);
// Close the JDBC connection
}
private static void writeTo(String str_xml,String as_filename) throws IOException
{

FileWriter out = new FileWriter("c:\\xml\\"+as_filename);
// System.out.println(" OUTPUT IS XML DATA :\n"+str_xml);
out.write(str_xml);
out.close();
}
}

Tom Kyte
November 22, 2002 - 4:52 pm UTC

Yeah, it seems that my DTDs that are being generated do not validate in XMLSpy. That's not a problem with the DTDs, it seems to be a problem in the way XMLSpy is trying to validate the DTD. It seems as if it's trying to validate an XML document, not a DTD. Since DTD's are not valid XML, the DTD seems to be invalid. Here's my sample based on a quick sample GenXMl class of my own:

<!DOCTYPE DEPARTMENTS [
<!ELEMENT DEPARTMENTS (DEPARTMENT)*>
<!ELEMENT DEPARTMENT (DEPARTMENT_NAME, MANAGER_ID?, EMPLOYEES)>
<!ATTLIST DEPARTMENT ID CDATA #REQUIRED>
<!ELEMENT DEPARTMENT_NAME (#PCDATA)>
<!ELEMENT MANAGER_ID (#PCDATA)>
<!ELEMENT EMPLOYEES (EMPLOYEES_ROW)*>
<!ELEMENT EMPLOYEES_ROW (EMPLOYEE_NAME?)>
<!ELEMENT EMPLOYEE_NAME (#PCDATA)>
]>

If you compare this with the recommendation or other W3C compliant DTDs, you'll see that it's just fine. I'm not sure why XMLSpy isn't working properly?


Where to start

A reader, November 22, 2002 - 5:30 pm UTC

Hi Sean ,
I am novice to XML and have oracle 9i Release2 .
Where do you want me to start learning XML ? like books etc

Thanks in Advance

Tom Kyte
November 22, 2002 - 7:24 pm UTC

DTD Problem

Ashok, November 23, 2002 - 9:43 am UTC

Thanks for answering the DTD issue.
I tried validating in Turbo XML from TIBCO i got the same error msg Internal subset not supported.I tried getting the XML schema using the function getXmlMetaData(SCHEMA)i got the same error using the above tools.
But the interseting thing is instead of using GetXmlMetaData i tried some thing like this

Doc arr[] = qry.getXmlSchema()
String ls_xsd
//Find the total elements in the array
for(i =1 ,i++ ,i <= Total elements in the array)
{
ls_xsd = ls_xsd + arr[i]
}

writeto(ls_xsd,"c:\xml\deals.xsd");

Output Generated from this one is succesfully vaidated against both the tools.Do you think this is the right way to generate the Metadata from the generated XML.

Thx
Ashok






Tom Kyte
November 27, 2002 - 9:28 am UTC

Yes, I'd say the "getXmlSchema" method would be the most appropriate way to get the XML Schema :-).

Tree Structure

Ken, January 24, 2003 - 11:56 am UTC

This example was very illuminating, but we have a variation on this problem where our data is in the form of a tree structure.
Could you provide an example of this using the Emp file tree structure (mgr/emp#)?
ie:
select e.name from emp e
start with e.mgr is null
connect by e.mgr = prior e.id

Smith & Doe work for King
Fudpucker works for Doe (not really in your table, but we like him)

Expected XML:

<Employee> <name> King</name>
<Employee><name> Smith</name> </Employee>
<Employee><name> Doe</name>
<Employee><name> Fudpucker</name></Employee>
</Employee>
</Employee>

Can this be done in a view?

Tom Kyte
January 29, 2003 - 1:53 pm UTC

Ken,
There is no out-of-the-box support for generating recursive nodes w/ a connect-by query. You could write a function to do what you're asking for, but it would involve either hand-generating the XML in a connect by for loop or using the XML parsers to dynamically construct the resulting XML document.

attribute-value in rowset tag

Umesh, March 18, 2003 - 11:08 pm UTC

Is there any way to insert attribute-value pair in ROWSET tag? The value is a sequence number.I am using oracle 9.0.1.

Tom Kyte
March 19, 2003 - 8:36 am UTC

In 9.0.1, the only way to accomplish what you're trying to do would be through the Java or PL/SQL DOM, or after generating the document using the XML SQL Utility and post-processing the XML document using XSLT (See ht tp://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1827993798549 and search for XSLT).

In Oracle9i Release 2, you can use new SQL extensions called "SQLX" (or SQLXML) to generate your XML documents. SQLX gives your VERY granular control over how your documents are created, and would most likely give you better performance than generating the document through the XML SQL Utility, then running it through the XSLT processor or loading the document up into an in-memory DOM to add attributes to the <ROWSET/> node(s). For more information on SQLX, see ht tp://otn.oracle.com/docs/products/oracle9i/doc_library/release2/appdev.920/a96620/xdb12gen.htm#1027862 or ht tp://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:6912626759561.

Hope that helps!

_smd_

attribute value in rowset tag

Umesh, March 19, 2003 - 4:36 pm UTC

Thanks for valuable suggestion. U saved lot of my time.

is it possible to generate this kind of xml from oracle?

Pravesh from India, April 27, 2003 - 5:34 am UTC

Tom/Sean Dillon

is it possible to generate this kind of xml from oracle?. (please see the below xml) ..If yes, which specific way of generating the xml i should follow. - Plsql Package or SQLX or XSU or ...?

from your above example i see that you use the object relation approach of creating types and varray - is this the best way to follow for my xml ?

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ematrix SYSTEM "ematrixml.dtd">
<ematrix>

<creationProperties>
<release>9.5.2.1-Global</release>
<datetime>2002-08-23T22:44:25Z</datetime>
<event>export</event>
<dtdInfo>&ematrixProductDtd;</dtdInfo>
</creationProperties>

<businessObject id="00000.00000.00000.00000">
<objectType>SII Project</objectType>
<objectName><![CDATA[Breakage Risk]]></objectName>
<objectRevision>1181033367349434</objectRevision>
<vaultRef>eService Production</vaultRef>
<policyRef>SII Project</policyRef>
<owner>
<userRef>103013592</userRef>
</owner>
<description><![CDATA[Project Owner = J. Castro ; Team Driving= ]]></description>
<creationInfo>
<datetime>2002-10-01T08:17:37Z</datetime>
</creationInfo>
<modificationInfo>
<datetime>2002-10-01T08:17:37Z</datetime>
</modificationInfo>
<attributeList count="4">
<attribute>
<name>Originator</name>
<string>103013592</string>
</attribute>
<attribute>
<name>Total Benefit CY1</name>
<string>-289</string>
</attribute>
<attribute>
<name>Is Funding Source Different</name>
<string>TRUE</string>
</attribute>
<attribute>
<name>Business Priority Code</name>
<string></string>
</attribute>
</attributeList>
<stateList count="4">
<state>
<name>Create</name>
<stateStatus>enabled</stateStatus>
</state>
<state>
<name>Assign</name>
<current/>
<stateStatus>enabled</stateStatus>
<actualInfo>
<datetime>2002-10-01T08:17:37Z</datetime>
</actualInfo>
</state>
<state>
<name>Evaluate</name>
<stateStatus>enabled</stateStatus>
</state>
<state>
<name>Approve</name>
<stateStatus>enabled</stateStatus>
</state>
</stateList>
<fromRelationshipList count="3">
<relationship>
<relationshipDefRef>Member</relationshipDefRef>
<relatedObject>
<businessObjectRef>
<objectType>Person</objectType>
<objectName>103013592</objectName>
<objectRevision>-</objectRevision>
<vaultRef>eService Production</vaultRef>
</businessObjectRef>
</relatedObject>
<attributeList count="2">
<attribute>
<name>Project Access</name>
<string>Project Owner</string>
</attribute>
<attribute>
<name>Project Role</name>
<string></string>
</attribute>
</attributeList>
</relationship>
<relationship>
<relationshipDefRef>SII Project Cost Item</relationshipDefRef>
<relatedObject>
<businessObjectRef>
<objectType>SII Cost Item</objectType>
<objectName><![CDATA[Breakage Risk]]></objectName>
<objectRevision>1201033367349434</objectRevision>
<vaultRef>eService Production</vaultRef>
</businessObjectRef>
</relatedObject>
</relationship>
<relationship>
<relationshipDefRef>SII Project Benefit Item</relationshipDefRef>
<relatedObject>
<businessObjectRef>
<objectType>SII Benefit Item</objectType>
<objectName><![CDATA[Breakage Risk]]></objectName>
<objectRevision>1191033367349434</objectRevision>
<vaultRef>eService Production</vaultRef>
</businessObjectRef>
</relatedObject>
</relationship>
</fromRelationshipList>
</businessObject>
</ematrix>

function TRANSFORM_XML_WITH_XSL

A reader, September 08, 2003 - 8:49 pm UTC

Tom,
Can the function TRANSFORM_XML_WITH_XSL be modified to return more than 1 XML file?

I have an XML file and XSL file. I would like to transform the single XML file into multiple XML files. Is that possible with the xslprocessor.processxsl or can this be done at all in Oracle using PL/SQL?


Thank you

Tom Kyte
September 09, 2003 - 11:24 am UTC

sorry, don't know -- don't really do very much with xml personally.

you can try devtrends.oracle.com -- Cameron O'Rourke is more of an "outside the database" guy and works with that stuff. He may have some ideas.

Richard

A reader, October 26, 2003 - 8:51 pm UTC

Hi Tom/Sean,

This is the first question I ever have submitted,

Oracle DBMS_XMLQUERY package generate canonical xml file like the following:
<?xml version="1.0" ?>
<ROWSET>
<ROW>
<FILE_ADD_COUNT>2</FILE_ADD_COUNT>
<FILE_MODIFY_COUNT></FILE_MODIFY_COUNT>

<TRAN_TYPE>A</TRAN_TYPE>
<DOC_TYPE>CR</DOC_TYPE>
<TRAN_TYPE>B</TRAN_TYPE>
<DOC_TYPE>CR</DOC_TYPE>
</ROW>
</ROWSET>

In order to generate a non-canonical xml per customer need for example
<?xml version="1.0" ?>
<FILE_HEADER>
<FILE_ADD_COUNT>2</FILE_ADD_COUNT>
<FILE_MODIFY_COUNT></FILE_MODIFY_COUNT>
<DETAIL>
<TRAN_TYPE>A</TRAN_TYPE>
<DOC_TYPE>CR</DOC_TYPE>
</DETAIL>
<DETAIL>
<TRAN_TYPE>B</TRAN_TYPE>
<DOC_TYPE>CR</DOC_TYPE>
</DETAIL>
</FILE_HEADER>

I use the the following XSLT clob, which does not make result xml clob return file_header info, what is wrong with this XSLT
and also how to make dbms_xmlquery package return
element even if element associated table column value is null

<xsl:stylesheet version="1.0" xmlns:xsl="</code> http://www.w3.org/1999/XSL/Transform" > <code>
<xsl:output indent="yes"/>
<xsl:template match="/">
<FILE_HEADER>
<FILE_ADD_COUNT><xsl:value-of select="FILE_ADD_COUNT"/></FILE_ADD_COUNT>
<FILE_MODIFY_COUNT><xsl:value-of select="FILE_MODIFY_COUNT"/></FILE_MODIFY_COUNT>
<xsl:for-each select="ROWSET/ROW">
<DETAIL>
<TRAN_TYPE><xsl:value-of select="TRAN_TYPE"/></TRAN_TYPE>
<DOC_TYPE><xsl:value-of select="DOC_TYPE"/></DOC_TYPE>
</DETAIL>
</xsl:for-each> <!-- ROWSET/ROW -->
</FILE_HEADER>
</xsl:template>
</xsl:stylesheet>';

Thanks for help and advice.

Tom Kyte
October 30, 2003 - 4:43 pm UTC

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

Hiya "a reader",

Yeah, your XSLT VALUE-OF elements are just a little off... Since you are matching "/" (<xsl:template match="/">) in the template, you have to fully qualify any element value you want to select from the match point. So instead of saying...

<FILE_MODIFY_COUNT><xsl:value-of select="FILE_MODIFY_COUNT"/></FILE_MODIFY_COUNT>

...you'd say...

<FILE_MODIFY_COUNT><xsl:value-of select="FILE_HEADER/FILE_MODIFY_COUNT"/></FILE_MODIFY_COUNT>

So for your example, your stylesheet would look like so:

<xsl:stylesheet version="1.0" xmlns:xsl="</code> http://www.w3.org/1999/XSL/Transform" > <code>
<xsl:output indent="yes"/>
<xsl:template match="/">
<FILE_HEADER>
<FILE_ADD_COUNT>
<xsl:value-of select="FILE_HEADER/FILE_ADD_COUNT"/>
</FILE_ADD_COUNT>
<FILE_MODIFY_COUNT>
<xsl:value-of select="FILE_HEADER/FILE_MODIFY_COUNT"/>
</FILE_MODIFY_COUNT>
<xsl:for-each select="FILE_HEADER/DETAIL">
<TRAN_TYPE><xsl:value-of select="TRAN_TYPE"/></TRAN_TYPE>
<DOC_TYPE><xsl:value-of select="DOC_TYPE"/></DOC_TYPE>
</xsl:for-each> <!-- DETAIL -->
</FILE_HEADER>
</xsl:template>
</xsl:stylesheet>

You can see in the <xsl:for-each select="FILE_HEADER/DETAIL"> stylesheet element, we only had to select "TRAN_TYPE" and "DOC_TYPE" from the source XML doc. This is because inside that <xsl:for-each/> we are selecting only the children of FILE_HEADER/DETAIL.

Hope that helps!

_smd_

the last question correction

RICHARD, October 27, 2003 - 8:23 pm UTC

Sorry, the source xml should look like following

Sorry, the question should be more simplier,

the source xml should be a number of records like

The source xml should be the following instead

<?xml version="1.0" ?>
<ROWSET>
<ROW>
<FILE_ADD_COUNT>3</FILE_ADD_COUNT>
<FILE_MODIFY_COUNT></FILE_MODIFY_COUNT>

<TRAN_TYPE>A</TRAN_TYPE>
<DOC_TYPE>CR</DOC_TYPE>
</ROW>
<ROW>
<FILE_ADD_COUNT>3</FILE_ADD_COUNT>
<FILE_MODIFY_COUNT></FILE_MODIFY_COUNT>

<TRAN_TYPE>B</TRAN_TYPE>
<DOC_TYPE>CR</DOC_TYPE>
</ROW>
<ROW>
<FILE_ADD_COUNT>3</FILE_ADD_COUNT>
<FILE_MODIFY_COUNT></FILE_MODIFY_COUNT>

<TRAN_TYPE>C</TRAN_TYPE>
<DOC_TYPE>CR</DOC_TYPE>
</ROW>
</ROWSET>


Tom Kyte
October 30, 2003 - 4:52 pm UTC

Hi Sean here again... so yeah, same concepts apply:

<xsl:stylesheet version="1.0" xmlns:xsl="</code> http://www.w3.org/1999/XSL/Transform" > <code>
<xsl:output indent="yes"/>
<xsl:template match="/">
<FILE_HEADER>
<xsl:for-each select="ROWSET/ROW">
<ROW>
<FILE_ADD_COUNT><xsl:value-of select="FILE_ADD_COUNT"/></FILE_ADD_COUNT>
<FILE_MODIFY_COUNT><xsl:value-of select="FILE_MODIFY_COUNT"/></FILE_MODIFY_COUNT>
<TRAN_TYPE><xsl:value-of select="TRAN_TYPE"/></TRAN_TYPE>
<DOC_TYPE><xsl:value-of select="DOC_TYPE"/></DOC_TYPE>
</ROW>
</xsl:for-each> <!-- ROW -->
</FILE_HEADER>
</xsl:template>
</xsl:stylesheet>

Good luck!

_smd_

And to a PDF

A reader, January 28, 2004 - 1:24 am UTC

Dear Tom/ Sean,
Thanks for this wonderful explaination!
Can "Transfrom_XML_with_XSL" be modified to output a PDF file?
What would be required to do this? Perhaps a XSL-FO processor (from Apache?) would need to be installed? How would this talk to PL/SQL then?
Any guidance is welcome.
Thanks

Tom Kyte
January 28, 2004 - 8:26 am UTC

getting outside the scope here --but yes, you would sort of need a pdf transforming piece of software. there isn't anything in the db to generate pdf out of the box.

Fruit of labor

Justin, June 18, 2004 - 9:24 am UTC

I just finished a hilarious program and thought I would share since it's so strange.
I was forced into writing it because of the design of the application we are trying to port to Oracle, and deadlines etc. This is one of many of these I have written and it is especially nasty.

I thought it might help someone else out there since I'd imagine nothing like this exists on the planet due to the nature of the situation.

The ultimate statement that could be made about why I had to do this is because our front end application was expecting "shaped XML" in a very specific format.

This program generates shaped XML in that very specific format and it does it supa-quick.

You can strip it down for your own use I'm sure, but all the hoops that I jump through are necessary. All the select from (select ..)s are required. And if you want to order by a column in the parent row... look out! You've got to do all that junk listed in the bottom FROM clause.

-enjoy :}


FUNCTION F_SYSSTFPRSNGETGRPLNKS(p_intt085id IN NUMBER)
RETURN CLOB
AS

l_sql CLOB;
l_sql2 CLOB;
l_ans sys.xmltype;
l_ans2 sys.xmltype;
l_clob CLOB;
f_clob CLOB;
n_clob CLOB;
x_clob CLOB;

BEGIN

-- DO NOT TOUCH THIS PROGRAM
-- JUSTIN STEWART

f_clob := '<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">';
n_clob := '<rs:data>';
x_clob := '</rs:data></xml>';

l_sql :=
'SELECT
XMLELEMENT("s:Schema", XMLATTRIBUTES( ''RowsetSchema'' as "id")
, XMLELEMENT("s:ElementType", XMLATTRIBUTES( ''row'' as "name")
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''T092_ID'' as "name", ''1'' as "rs:number", ''T092_USER_AUTH'' as "rs:basetable", ''T092_ID'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''number'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''T085_ID'' as "name", ''2'' as "rs:number", ''T092_USER_AUTH'' as "rs:basetable", ''T085_ID'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''number'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''T084_ID'' as "name", ''3'' as "rs:number", ''T092_USER_AUTH'' as "rs:basetable", ''T084_ID'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''number'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''ORIGINAL_T084_ID'' as "name", ''4'' as "rs:number", ''T083_GRP_CTG_LINK'' as "rs:basetable", ''ORIGINAL_T084_ID'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''number'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''SECURITY_GRP_NM'' as "name", ''5'' as "rs:number", ''T083_GRP_CTG_LINK'' as "rs:basetable", ''SECURITY_GRP_NM'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''string'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''MAX_CLINIC_PERM'' as "name", ''6'' as "rs:number", ''T083_GRP_CTG_LINK'' as "rs:basetable", ''MAX_CLINIC_PERM'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''string'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''MAX_LA_PERM'' as "name", ''7'' as "rs:number", ''T083_GRP_CTG_LINK'' as "rs:basetable", ''MAX_LA_PERM'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''string'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''MAX_STATE_PERM'' as "name", ''8'' as "rs:number", ''T083_GRP_CTG_LINK'' as "rs:basetable", ''T042_STATUS_CD'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''string'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''Id'' as "name", ''9'' as "rs:number")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''uuid'' as "dt:type", ''true'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''WEB_STATUS'' as "name", ''10'' as "rs:number")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''string'' as "dt:type", ''true'' as "rs:maybenull")))
, XMLELEMENT("s:ElementType", XMLATTRIBUTES( ''category'' as "name")
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''T084_ID'' as "name", ''11'' as "rs:number", ''T083_GRP_CTG_LINK'' as "rs:basetable", ''T084_ID'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''number'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''CLINIC_LVL_ACC_CD'' as "name", ''12'' as "rs:number", ''T083_GRP_CTG_LINK'' as "rs:basetable", ''CLINIC_LVL_ACC_CD'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''string'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''LA_LVL_ACC_CD'' as "name", ''13'' as "rs:number", ''T083_GRP_CTG_LINK'' as "rs:basetable", ''LA_LVL_ACC_CD'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''string'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''STATE_LVL_ACC_CD'' as "name", ''14'' as "rs:number", ''T083_GRP_CTG_LINK'' as "rs:basetable", ''STATE_LVL_ACC_CD'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''string'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''T104_ID'' as "name", ''15'' as "rs:number", ''T104_CATEGORIES'' as "rs:basetable", ''T104_ID'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''number'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''CATEGORY_NM'' as "name", ''16'' as "rs:number", ''T104_CATEGORIES'' as "rs:basetable", ''CATEGORY_NM'' as "rs:basecolumn")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''string'' as "dt:type", ''false'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''Id'' as "name", ''17'' as "rs:number")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''uuid'' as "dt:type", ''true'' as "rs:maybenull")))
, XMLELEMENT("s:AttributeType", XMLATTRIBUTES( ''WEB_STATUS'' as "name", ''18'' as "rs:number")
, XMLELEMENT("s:datatype", XMLATTRIBUTES( ''string'' as "dt:type", ''true'' as "rs:maybenull"))))))
FROM DUAL';

l_sql2 := 'SELECT(XMLAGG( XMLELEMENT( "z:row", XMLATTRIBUTES ( t2.t092_id AS "T092_ID"
, t2.t085_id AS "T085_ID"
, t2.t084_id AS "T084_ID"
, t2.original_t084_id AS "ORIGINAL_T084_ID"
, t2.security_grp_nm AS "SECURITY_GRP_NM"
, CASE (SELECT NVL(MAX(CASE t083.clinic_lvl_acc_cd
WHEN ''P'' THEN 3
WHEN ''U'' THEN 2
WHEN ''I'' THEN 1
ELSE 0
END), 0)
FROM t083_grp_ctg_link t083 JOIN t104_categories t104 ON t083.t104_id = t104.t104_id
WHERE t083.t084_id = t2.t084_id
AND t104.category_nm NOT LIKE ''%MODULE%'')
WHEN 3 THEN ''P''
WHEN 2 THEN ''U''
WHEN 1 THEN ''I''
ELSE ''N''
END "MAX_CLINIC_PERM"
, CASE (SELECT NVL(MAX(CASE t083.la_lvl_acc_cd
WHEN ''P'' THEN 3
WHEN ''U'' THEN 2
WHEN ''I'' THEN 1
ELSE 0
END), 0)
FROM t083_grp_ctg_link t083 JOIN t104_categories t104 ON t083.t104_id = t104.t104_id
WHERE t083.t084_id = t2.t084_id
AND t104.category_nm NOT LIKE ''%MODULE%'')
WHEN 3 THEN ''P''
WHEN 2 THEN ''U''
WHEN 1 THEN ''I''
ELSE ''N''
END "MAX_LA_PERM"
, CASE (SELECT NVL(MAX(CASE t083.state_lvl_acc_cd
WHEN ''P'' THEN 3
WHEN ''U'' THEN 2
WHEN ''I'' THEN 1
ELSE 0
END), 0)
FROM t083_grp_ctg_link t083 JOIN t104_categories t104 ON t083.t104_id = t104.t104_id
WHERE t083.t084_id = t2.t084_id
AND t104.category_nm NOT LIKE ''%MODULE%'')
WHEN 3 THEN ''P''
WHEN 2 THEN ''U''
WHEN 1 THEN ''I''
ELSE ''N''
END "MAX_STATE_PERM"
, newid() AS "Id"
, '' '' AS "WEB_STATUS")
, (SELECT XMLAGG(XMLELEMENT ("category", XMLATTRIBUTES ( t3.t084_id AS "T084_ID"
, t3.clinic_lvl_acc_cd AS "CLINIC_LVL_ACC_CD"
, t3.la_lvl_acc_cd AS "LA_LVL_ACC_CD"
, t3.state_lvl_acc_cd AS "STATE_LVL_ACC_CD"
, t3.t104_id AS "T104_ID"
, t3.category_nm AS "CATEGORY_NM"
, newid() AS "Id"
, '' '' AS "WEB_STATUS")))
FROM (SELECT innert1.t084_id
, innert1.clinic_lvl_acc_cd
, innert1.la_lvl_acc_cd
, innert1.state_lvl_acc_cd
, innert2.t104_id
, innert2.category_nm
FROM t083_grp_ctg_link innert1 JOIN t104_categories innert2 ON innert1.t104_id = innert2.t104_id
UNION
SELECT DISTINCT
innert2.t084_super_grp_id as "t084_id"
, innert3.clinic_lvl_acc_cd
, innert3.la_lvl_acc_cd
, innert3.state_lvl_acc_cd
, innert4.t104_id
, innert4.category_nm
FROM t084_security_grp innert1 JOIN t117_super_group innert2 ON innert1.t084_id = innert2.t084_dependent_id
JOIN t083_grp_ctg_link innert3 ON innert1.t084_id = innert3.t084_id
JOIN t104_categories innert4 ON innert3.t104_id = innert4.t104_id) t3
WHERE t2.t084_id = t3.t084_id) )))
FROM (SELECT t100.t092_id
, t100.t084_id
, t100.t085_id
, t100.original_t084_id
, t100.t084_status_cd
, t100.security_grp_nm
, t100.super_group_in
FROM (SELECT t1.t092_id
, t1.t084_id
, t1.t085_id
, t2.t084_id original_t084_id
, t2.t084_status_cd
, t2.security_grp_nm
, t2.super_group_in
FROM t092_user_auth t1 RIGHT JOIN t084_security_grp t2 ON t1.t084_id = t2.t084_id
AND t1.t085_id = '||p_intt085id||') t100
ORDER BY t100.security_grp_nm DESC) t2';


-- USE TO DEBUG SELECT
--l_clob := l_sql;

EXECUTE IMMEDIATE TO_CHAR(l_sql) INTO l_ans;
EXECUTE IMMEDIATE TO_CHAR(l_sql2) INTO l_ans2;

-- USE THIS LINE to ensure the first l_sql is executing properly. You must comment out the execute immediate for l_sql2 above when debugging for this.
--l_clob := f_clob || l_ans.getClobVal() || n_clob || x_clob;

l_clob := f_clob || l_ans.getClobVal() || n_clob || l_ans2.getClobVal() || x_clob;

RETURN l_clob;

END F_SYSSTFPRSNGETGRPLNKS;



---

EOF

xml result

A reader, March 08, 2005 - 11:32 am UTC

Hi,

I have the following:

create table testxml
(
id varchar2(12),
imagedate date
);

insert into testxml values ('1000021', sysdate);
insert into testxml values ('3214566', sysdate);
insert into testxml values ('6543788', sysdate);
commit;

declare
TQUERY VARCHAR2(5000);
Tqryctx DBMS_XMLGEN.CTXHANDLE;
pres clob;
begin
tquery := 'select imagedate "Printdate", id from testxml ';
Tqryctx := DBMS_XMLGEN.NEWCONTEXT(TQUERY);
dbms_xmlgen.setrowtag(Tqryctx, 'Printdate');
PRES := DBMS_XMLGEN.GETXML(Tqryctx);
DBMS_XMLGEN.CLOSECONTEXT(Tqryctx);
printclobout (pres);
end;
/

When I execute the above, I am getting the result as:

| <?xml version="1.0"?>
| <ROWSET>
| <Printdate>
| <Printdate>03-08-2005 11:24:38</Printdate>
| <ID>1000021</ID>
| </Printdate>
| <Printdate>
| <Printdate>03-08-2005 11:24:52</Printdate>
| <ID>3214566</ID>
| </Printdate>
| <Printdate>
| <Printdate>03-08-2005 11:25:05</Printdate>
| <ID>6543788</ID>
| </Printdate>
| </ROWSET>

PL/SQL procedure successfully completed.

But I want something like
| <?xml version="1.0"?>
| <ROWSET>
| <Printdate = "03-08-2005">
| <ID>1000021</ID>
| <ID>3214566</ID>
| <ID>6543788</ID>
| </Printdate>
| </ROWSET>

Thanks.



Tom Kyte
March 08, 2005 - 1:39 pm UTC

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

First, in Oracle9iR2 and beyond you should be using SQLXML.  This is by far the best and easiest mechanism to generate XML data from your pre-existing relational/object data.  XMLGEN isn't really necessary and it doesn't have the flexibility of SQLXML.  You can search AskTom for more info on SQLXML, it's been discussed here A LOT.

Second, the XML you're trying to create isn't XML at all, it's invalid XML :).  Your <Printdate> element can't = "03-08-2005", only an attribute of the element can equal that value inside the brackets.  So in the response below, I added an attribute to that element to keep it well-formed.  I also noticed an issue w/ your test data.  You only show a single date.  If you have more than one date you can either have more nodes in the same ROWSET element, or you can have multiple documents.  Let me show you...

Using your test data, this query:

SQL> select xmlelement( "ROWSET",
  2           xmlelement( "Printdate",
  3             xmlattributes(t1.imagedate as "TheDate"),
  4             ( select xmlagg(xmlelement(id,t2.id))
  5                 from testxml t2
  6                where to_char(t2.imagedate,'MM-DD-YYYY') = t1.imagedate ) )
  7           )
  8    from ( select distinct to_char(imagedate,'MM-DD-YYYY') imagedate
  9             from testxml ) t1
 10  /

...yields your result...

XMLELEMENT("ROWSET",XMLELEMENT("PRINTDATE",XMLATTRIBUTES(T1.IMAGEDATEAS"THEDATE"),(SELECTXMLAGG(XMLE
----------------------------------------------------------------------------------------------------
<ROWSET>
  <Printdate TheDate="03-08-2005">
    <ID>1000021</ID>
    <ID>3214566</ID>
    <ID>6543788</ID>
  </Printdate>
</ROWSET>

If I add some more data, however...

SQL> insert into testxml values ('3214566', sysdate-5);
1 row created.

SQL> insert into testxml values ('6543788', sysdate-5);
1 row created.

...and reexecute the query, I get TWO XML documents:

SQL> select xmlelement( "ROWSET",
  2           xmlelement( "Printdate",
  3             xmlattributes(t1.imagedate as "TheDate"),
  4             ( select xmlagg(xmlelement(id,t2.id))
  5                 from testxml t2
  6                where to_char(t2.imagedate,'MM-DD-YYYY') = t1.imagedate ) )
  7           )
  8    from ( select distinct to_char(imagedate,'MM-DD-YYYY') imagedate
  9             from testxml ) t1
 10  /

XMLELEMENT("ROWSET",XMLELEMENT("PRINTDATE",XMLATTRIBUTES(T1.IMAGEDATEAS"THEDATE"),(SELECTXMLAGG(XMLE
----------------------------------------------------------------------------------------------------
<ROWSET>
  <Printdate TheDate="03-03-2005">
    <ID>3214566</ID>
    <ID>6543788</ID>
  </Printdate>
</ROWSET>

<ROWSET>
  <Printdate TheDate="03-08-2005">
    <ID>1000021</ID>
    <ID>3214566</ID>
    <ID>6543788</ID>
  </Printdate>
</ROWSET>


If you only want one document w/ multiple <Printdate/> nodes, use XMLAGG to aggregate multiple nodes returned in a query into a single document:


SQL> select xmlelement( "ROWSET",
  2           xmlagg( xmlelement( "Printdate",
  3                     xmlattributes(t1.imagedate as "TheDate"),
  4                     ( select xmlagg(xmlelement(id,t2.id))
  5                         from testxml t2
  6                        where to_char(t2.imagedate,'MM-DD-YYYY') = t1.imagedate ) )
  7                 ) )
  8    from ( select distinct to_char(imagedate,'MM-DD-YYYY') imagedate
  9             from testxml ) t1
 10  /

XMLELEMENT("ROWSET",XMLAGG(XMLELEMENT("PRINTDATE",XMLATTRIBUTES(T1.IMAGEDATEAS"THEDATE"),(SELECTXMLA
----------------------------------------------------------------------------------------------------
<ROWSET>
  <Printdate TheDate="03-03-2005">
    <ID>3214566</ID>
    <ID>6543788</ID>
  </Printdate>
  <Printdate TheDate="03-08-2005">
    <ID>1000021</ID>
    <ID>3214566</ID>
    <ID>6543788</ID>
  </Printdate>
</ROWSET>

Hope that helps...

_smd_

Sean Dillon
 

A reader, March 08, 2005 - 5:10 pm UTC

this query works great. thanks a lot. if I want to assign the output of this query into a variable should I assign it to a clob variable? pls let me know.

Thanks.

Tom Kyte
March 09, 2005 - 9:35 am UTC

Hi, Sean here. It's going to be an XMLType out of the query (XMLELEMENT returns XMLType). You could either assign it to an XMLType or to a CLOB, depending on what your application needs. Here are a couple of examples:

sdillon@JBLADE> declare
2 l_xml xmltype;
3 l_xmlclob clob;
4 begin
5 -- ASSIGN TO AN XMLTYPE
6 select xmlelement( "ROWSET",
7 xmlagg( xmlelement( "Printdate",
8 xmlattributes(t1.imagedate as "TheDate"),
9 ( select xmlagg(xmlelement(id,t2.id))
10 from testxml t2
11 where to_char(t2.imagedate,'MM-DD-YYYY') =
12 t1.imagedate ) )
13 ) )
14 into l_xml
15 from ( select distinct to_char(imagedate,'MM-DD-YYYY') imagedate
16 from testxml ) t1;
17
18 -- OR A CLOB
19 select xmlelement( "ROWSET",
20 xmlagg( xmlelement( "Printdate",
21 xmlattributes(t1.imagedate as "TheDate"),
22 ( select xmlagg(xmlelement(id,t2.id))
23 from testxml t2
24 where to_char(t2.imagedate,'MM-DD-YYYY') =
25 t1.imagedate ) )
26 ) ).getClobVal()
27 into l_xmlclob
28 from ( select distinct to_char(imagedate,'MM-DD-YYYY') imagedate
29 from testxml ) t1;
30 end;
31 /

PL/SQL procedure successfully completed.

Unformated output

giri, March 09, 2005 - 3:30 am UTC

Hello Tom,
       I am trying to run DBMS_XMLGen and i am not able to get the output in a proper format. Can you please let me know what is the problem?

       Here is it.


SQL> declare
  2        qryctx dbms_xmlgen.ctxhandle;
  3      begin
  4        -- notice SELECT *: just take the defaults
  5        qryctx := dbms_xmlgen.newcontext('select * from customer_view');
  6        dbms_xmlgen.setrowsettag(qryctx,'PeopleList');
  7        dbms_xmlgen.setrowtag(qryctx,'Employees');
  8        :c := dbms_xmlgen.getxml(qryctx);
  9      end;
 10  /

PL/SQL procedure successfully completed.


C
--------------------------------------------------------------------------------
<?xml version="1.0"?>
<PeopleList>
 <Employees>
  <CUSTOMER_NO>1</CUSTOMER_NO>

 <CUSTOMER_NAME>Jean Nance</CUSTOMER_NAME>
  <ADDRESS>
   <STREET>2 Avocet Drive
</STREET>
   <CITY>Redwood Shores</CITY>
   <STATE>CA</STATE>
   <ZIP>95054</ZIP
>
  </ADDRESS>
  <PHONE_LIST>
   <VARCHAR2>415-555-1212</VARCHAR2>
   <VARCHAR2>
650-123-3456</VARCHAR2>
   <VARCHAR2>609-555-1212</VARCHAR2>
   <VARCHAR2>201-55
5-1212</VARCHAR2>
  </PHONE_LIST>
 </Employees>
 <Employees>
  <CUSTOMER_NO>2</C
USTOMER_NO>
  <CUSTOMER_NAME>John Nike</CUSTOMER_NAME>
  <ADDRESS>
   <STREET>32
3 College Drive</STREET>
   <CITY>Edison</CITY>
   <STATE>NJ</STATE>
   <ZIP>088
20</ZIP>
  </ADDRESS>
  <PHONE_LIST>
   <VARCHAR2>609-555-1212</VARCHAR2>
   <VA
RCHAR2>201-555-1212</VARCHAR2>
   <VARCHAR2>415-555-1212</VARCHAR2>
   <VARCHAR2
>650-123-3456</VARCHAR2>
  </PHONE_LIST>
 </Employees>
</PeopleList>
 

Tom Kyte
March 09, 2005 - 7:46 am UTC

that looks like sqlplus wrapping it, play with

set long ....
set linesize .....

clob output

A reader, March 09, 2005 - 10:09 am UTC

Hi Sean,

Thanks for the followup. I tried a similar piece of code like how you suggested and I am getting the following output.

declare
l_xmlclob clob;
begin
select xmlelement( "ROWSET",
xmlagg( xmlelement( "Printdate",
xmlattributes(t1.imagedate as "TheDate"),
( select xmlagg(xmlelement(id,t2.id))
from testxml t2
where to_char(t2.imagedate,'MM-DD-YYYY') =
t1.imagedate ) )
) ).getClobVal()
into l_xmlclob
from ( select distinct to_char(imagedate,'MM-DD-YYYY') imagedate
from testxml ) t1;
printclobout(l_xmlclob);
end;
/

When I execute this piece of code I am getting the output as

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

Pls help.

Thanks.

Tom Kyte
March 09, 2005 - 10:46 am UTC

well... do the query outside of plsql. then check your printclobout procedure. not sure why you're getting no data back.

_smd_

varchar2 works

A reader, March 09, 2005 - 11:32 am UTC

Hi Sean,

Somehow if I change the datatype of the output variable into a varchar2 rather than clob I am able to see the output when I display it. Is that fine? Can I use varchar2 as the output datatype?

Thanks.

Tom Kyte
March 09, 2005 - 2:58 pm UTC

It seems to be working for you :).

SQLXML

A reader, March 11, 2005 - 10:30 am UTC

Hi,

In this article, Sean said that

"First, in Oracle9iR2 and beyond you should be using SQLXML. This is by far the
best and easiest mechanism to generate XML data from your pre-existing
relational/object data. XMLGEN isn't really necessary and it doesn't have the
flexibility of SQLXML. You can search AskTom for more info on SQLXML, it's been
discussed here A LOT."

I have a lot of procedures which do something like the foll

tqry := 'select lname, fname, gender, dob, ssn, empid, empname from emp where id = :id1';
(We have like very large queries not as simple as shown above)
tctx := dbms_xmlquery.newcontext(tqry);
tclobout := dbms_xmlquery.getxml(tctx);
dbms_xmlquery.closecontext(tctx);

Would you suggest me to rewrite all this code using SQLXML and can you give me an example of how to do that.

Thanks.



Tom Kyte
March 11, 2005 - 11:17 am UTC

Sean here.. Well... this is obviously a judgement call. You have to weigh the pros and cons of switching over from XMLQUERY to SQLXML. SQLXML is definitely more robust and should net you better performance (although take that statement with a grain of salt, testing and benchmarking is the only way to know that for sure)... if it means rebuilding hundreds of extremely complex, large queries then is the payoff good enough?

I wouldn't be able to say yes or no unless I knew (1) how much work it would be to switch them _and_ (2) what kind of benefit this would gain my customer in terms of performance and flexibility of the XML. Only then could I make a relatively well-informed decision.

The query you posted is trivial, obviously, but something very complex or based on object queries in the database... those get a touch more tricky to write in SQLXML. Not impossible mind you but definitely not trivial.

_smd_

A reader, March 15, 2006 - 12:00 pm UTC

Hi Tom/Sean,

I have a procedure which generates XML from a dynamic SQL Statement and the XML is in the following format:

<?xml version = '1.0'?>
<ROWSET>
<ROW num="1">
<DEMXML>
<TIMESTAMP>2/17/2000 0:0:0</TIMESTAMP>
<RACEVAL>B</RACEVAL>
<LASTNAME>ROSS</LASTNAME>
<MIDDLENAME>A</MIDDLENAME>
<SEX>F</SEX>
<SSN NULL="TRUE"/>
<HEIGHT>507</HEIGHT>
<WEIGHT>180</WEIGHT>
</DEMXML>
</ROW>
</ROWSET>

Is there any way by which I can regenerate this XML without the DEMXML tag like

<?xml version = '1.0'?>
<ROWSET>
<ROW num="1">
<TIMESTAMP>2/17/2000 0:0:0</TIMESTAMP>
<RACEVAL>B</RACEVAL>
<LASTNAME>ROSS</LASTNAME>
<MIDDLENAME>A</MIDDLENAME>
<SEX>F</SEX>
<SSN NULL="TRUE"/>
<HEIGHT>507</HEIGHT>
<WEIGHT>180</WEIGHT>
</ROW>
</ROWSET>

Thanks.

Tom Kyte
March 15, 2006 - 5:23 pm UTC

where is the "demxml" coming from in the first place.

A reader, March 15, 2006 - 6:04 pm UTC

Hi Tom,

I am generating the XML clob using an SQL Statement like the following :

select d_t(a.timestamp, a.race , a.lastname, a.middlename, a.sex, a.ssn, a.height, a.weight) as demxml
from demdata a where a.id = 46;

where d_t is a type created as

CREATE TYPE d_t AS OBJECT(
timestamp date,
raceval varchar2(4),
lastname varchar2(25),
middlename varchar2(25),
sex char(1),
ssn varchar2(9),
height varchar2(4),
weight varchar2(4)
);


Thanks.

Tom Kyte
March 16, 2006 - 7:40 am UTC

don't cast it as the object type, just get rid of d_t( ... )

Continuation to previous response -- Additional explanation

A reader, March 16, 2006 - 7:28 am UTC

Hi Tom,

In addition to explaining how I got demxml above, I also wanted to add the following. You might think that I dont need even need a type there and hence I can avoid the alias demxml but I just wanted to say that I am having a nested type inside the type d_t which I have not included in the xml for simplicity purposes. So I do need that alias demxml......

Please help.

Tom Kyte
March 16, 2006 - 2:23 pm UTC

give real example, not fake one - I don't see why having a nested type makes a bit of difference.

Please see additional explanation Tom

A reader, March 16, 2006 - 9:52 am UTC

I have explained why I am casting as the object type and why I cannot get rid of d_t(....)


Tom Kyte
March 16, 2006 - 2:33 pm UTC

no you haven't...

If it is there, it will be part of the output, you haven't shown me why it is there.

removing it will be the way to get rid of it.

Displaying NULL values with SQLX

Claude, March 28, 2006 - 2:06 pm UTC

Hi Tom,
Following up on an earlier example, I was going to use SQLX in place of XSU.
Here are the create, insert, and SQLX commands:

create table customer_tab(
customer_no number,
customer_name varchar2(200),
street varchar2(200),
city varchar2(200),
state char(2),
zip varchar2(20),
phone1 varchar2(20),
phone2 varchar2(20),
phone3 varchar2(20),
phone4 varchar2(20),
constraint customer_pk primary key (customer_no)
);

insert into customer_tab values
(1, 'Jean Nance', '2 Avocet Drive',
'Redwood Shores', 'CA', '95054',
'415-555-1212', '650-123-3456',
null, null);

insert into customer_tab values
(2, 'John Nike', '323 College Drive',
'Edison', 'NJ', '08820',
'609-555-1212', '201-555-1212',
null, null);

select xmlelement("customer",
xmlattributes(customer_no as "number",
customer_name as "name",
phone1 as "phone_1",
phone2 as "phone_2",
phone3 as "phone_3",
phone4 as "phone_4")
)
from customer_tab;


select xmlelement("customer",
xmlforest(customer_no as "number"),
xmlforest(customer_name as "name"),
xmlforest(phone1 as "phone_1"),
xmlforest(phone2 as "phone_2"),
xmlforest(phone3 as "phone_3"),
xmlforest(phone4 as "phone_4")
)
from customer_tab;

My question is: How do I get the null phone_3 and phone_4 attributes and elements to appear in the XML results? (such as <....phone_3="" phone_4=""/> or <phone4/>, etc)
I'm on using SQL*Plus 9.0.2.5.0.
Thanks


Displaying NULL values with SQLX

Claude, March 29, 2006 - 11:18 am UTC

No response? I guess I've stumped the chump :-P

Tom Kyte
March 29, 2006 - 11:38 am UTC

I see xml and mostly read on past it. I don't use that part of the database.

and Sean doesn't work here anymore.



Displaying NULL values with SQLX

Claude, March 29, 2006 - 12:16 pm UTC

Sorry to learn about Sean's leaving. It's a big loss to AskTom. I hope we didn't chase him away.

Tom Kyte
March 29, 2006 - 12:42 pm UTC

nah, he left to chase greener pastures across the street (literally - he works across the street). I'll let him know this friday at poker :)

xmlagg output from a reader post above

mooshoo, June 05, 2006 - 5:20 pm UTC

Hi Tom,

I read the above post from Mar 9, 2005 where the foll query was suggested to "reader" (query shown below). I am trying something similar like that but I am not seeing the full output of the query in SQL* Plus and the output is getting truncated in the middle itself. What are the parameters that I have to look into in order to see the full output. Please help.

declare
l_xmlclob clob;
begin
select xmlelement( "ROWSET",
xmlagg( xmlelement( "Printdate",
xmlattributes(t1.imagedate as "TheDate"),
( select xmlagg(xmlelement(id,t2.id))
from testxml t2
where to_char(t2.imagedate,'MM-DD-YYYY') =
t1.imagedate ) )
) ).getClobVal()
into l_xmlclob
from ( select distinct to_char(imagedate,'MM-DD-YYYY') imagedate
from testxml ) t1;
printclobout(l_xmlclob);
end;
/

Thanks.

Tom Kyte
June 05, 2006 - 6:46 pm UTC

SQL> set long 500000 

Inserting data into multiple tables(Oracle Version 9.2.0.6)

Vinayak, February 13, 2007 - 5:47 pm UTC

Hi Tom,

we are going to receive the following XML file from one of our vendor. We need to parse the file and then save the data to multiple database tables (around 3).

<?xml version="1.0"?>
<datafeed xmlns:xsi="ht tp://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="DailyFeed.xsd" deliverydate="2007-02-14T00:00:00" vendorid="4">
<items count="1">
<item feed_id="001379" mode="MERGE">
<content empbased="true">
<emp>10000000</emp>
<value>
</value>
<date>2006-01-16</date>
<unit>CHF</unit>
<links>
<link lang="EN">
<url>www.pqr.com</url>
<description>pqr website</description>
</link>
<link lang="DE">
<url>www.efg.com</url>
<description>efg website</description>
</link>
</links>
</content>
<content empbased="true">
<emp>10000001</emp>
<value>
</value>
<date>2006-01-16</date>
<unit>CHF</unit>
<links>
<link lang="EN">
<url>www.abc.com</url>
<description>abc website</description>
</link>
<link lang="DE">
<url>www.xyz.com</url>
<description>xyz website</description>
</link>
</links>
</content>
<content empbased="true">
<emp>10000002</emp>
<value>
</value>
<date>2006-01-16</date>
<unit>CHF</unit>
<links>
<link lang="IT">
<url>www.rst.com</url>
<description>rst website</description>
</link>
</links>
</content>
</item>
</items>
</datafeed>

Now the operation to be done on the table depends on the mode attribute. Further, there are some basic validations need to be done using count attribute. Here the item tag, content tag & link tag are recurring elements.

The problem is I am not able to find the correct attributes like mode, feed_id, lang through SQL query(they are getting duplicated) though I was able to find the deliverydate & vendorid attribute as they are non-repeatitive. Here are the scripts :

create table tbl_xml_rawdata (xml_content xmltype);

create directory xmldir as 'c:\xml';
--put the above xml file in this directory and name it testfile.xml

Declare
l_bfile BFILE;
l_clob CLOB;
BEGIN
l_bfile := BFileName('XMLDIR', 'testfile.xml');
dbms_lob.createtemporary(l_clob, cache=>FALSE);
dbms_lob.open(l_bfile, dbms_lob.lob_readonly);
dbms_lob.loadFromFile(dest_lob => l_clob,
src_lob => l_bfile,
amount => dbms_lob.getLength(l_bfile));
dbms_lob.close(l_bfile);
insert into test_xml_rawdata values(xmltype.createxml(l_clob));
commit;
end;

My query is:

select extractvalue(value(b),'/datafeed/@deliverydate') ddate, extractvalue(value(b),'/datafeed/@vendorid') vendorid,
extractvalue( value( c ), '//@feed_id') feed_id,
extractvalue( value( a ), '//@empbased') empbased,
extractvalue( value( a ), '//emp') emp,
extractvalue( value( a ), '//value') value,
extractvalue( value( a ), '//unit') unit,
extractvalue( value( a ), '//date') ddate1,
extract( value( a ), '//links/link/url') url,
extract( value( a ), '//links/link/description') description
from tbl_xml_rawdata t,
table(xmlsequence(extract(t.xml_content,'/datafeed/items/item/content'))) a,
table(xmlsequence(extract(t.xml_content,'/'))) b ,
table(xmlsequence(extract(t.xml_content,'/datafeed/items/item'))) c;

If you the run the above query, the feed_id is cartesian joined with other data ,which is wrong.

How should I go with this so that I can have 1 relational record with respect to each element & sub-elements.

Also, if this is not doable in SQL, can you direct me to some plsql example to do this. I read that dbms_xmldom & dbms_xmlparser can be used to travel through XML doc but I don't know how to use them.

Waiting for your reply, Tom.


XSL Transform in 10g (release 1 and 2)

Carlos, April 23, 2007 - 7:22 am UTC

Hi Tom,
We're using XMLTransform utility to transform some XML documents generated from the DB using XMLElement function mainly into another XML especification since almost 2 years in a oracle 9 database.
Reciently, we have upgrated to 10g relaase and we have experience some problems with the xls:attribute tag. The behavior has changed and the transformation engine seems to ignore all the xsl:attribute instructions present in the xsl style sheet. The resulting xml does not show any attribute tag inside elementes.

My stile sheet seems like

<xsl:stylesheet version="1.0" xmlns:xsl=" http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="text" indent="yes" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" encoding="UTF-8"/>
<xsl:template match="*">
<xsl:element name="tr">
<xsl:for-each select="*">
<xsl:element name="td">
<xsl:if test="@class">
<xsl:attribute name="class">
<xsl:value-of select="@class"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="@num">
<xsl:attribute name="num">
<xsl:value-of select="@num"/>
</xsl:attribute>
</xsl:if>
<xsl:value-of select="normalize-space()"/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

and the test query we are using looks like:

SELECT XMLTransform(XMLQRY.XML_ROW, TSTYLES.STYLE_SHEET).getClobVal()
FROM TSTYLES,
(
SELECT XMLElement("tr",
XMLElement("td", XMLAttributes('snt' AS "class"),SQLQRY.name),
XMLElement("td", XMLAttributes('snt' AS "class"),SQLQRY.age)) AS XML_ROW
FROM (
SELECT TAB1.MAIN_NAME AS NAME,
TAB1.AGE AS AGE
FROM PERSON TAB1
WHERE TAB1.AGE BETWEEN 20 AND 30
)SQLQRY
)XMLQRY
WHERE TSTYLES.STYLE_NAME = 'TEST'

I was enable to find any reference of this subject in the forum. Could you please give me your opinion?

Thanks
Carlos

XSL Transform in 10g (release 10.2.0.3)

Carlos, April 23, 2007 - 12:41 pm UTC

Post a simple test-case

SELECT XMLTransform(XMLQRY.XML_ROW,
XMLType('<xsl:stylesheet version="1.0" xmlns:xsl=" http://www.w3.org/1999/XSL/Transform" >'||
'<xsl:output method="text" indent="yes" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" encoding="UTF-8"/>'||
'<xsl:template match="*">'||
'<xsl:element name="tr">'||
'<xsl:for-each select="*">'||
'<xsl:element name="td">'||
'<xsl:if test="@class">'||
'<xsl:attribute name="class">'||
'<xsl:value-of select="@class"/>'||
'</xsl:attribute>'||
'</xsl:if>'||
'<xsl:if test="@num">'||
'<xsl:attribute name="num">'||
'<xsl:value-of select="@num"/>'||
'</xsl:attribute>'||
'</xsl:if>'||
'<xsl:value-of select="normalize-space()"/>'||
'</xsl:element>'||
'</xsl:for-each>'||
'</xsl:element>'||
'</xsl:template>'||
'</xsl:stylesheet>')).getClobVal()
FROM (
SELECT XMLElement("tr",
XMLElement("NAME", XMLAttributes('snt' AS "class"),SQLQRY.name),
XMLElement("AGE" , XMLAttributes('snt' AS "class"),SQLQRY.age)
) AS XML_ROW
FROM ( SELECT 'MY_NAME' AS NAME,
'27' AS AGE
FROM DUAL ) SQLQRY
)XMLQRY

XSL Transform in 10g (release 10.2.0.3)

Carlos, April 23, 2007 - 12:49 pm UTC

Here is the mistake (maybe a bug?)

'<xsl:output method="text" indent="yes" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" encoding="UTF-8"/>'||

the xsl:output method must be expresed as

'<xsl:output method="xml" indent="yes" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" encoding="UTF-8"/>'||

to get the attributes. Anyway, i get it working in previous releases.

Thanks for your time.


generate xml without header oracle 9i Release 1

Jaspreet, August 20, 2008 - 12:22 pm UTC

Hi Tom And Sean,

I am a novoice to Oracle. I am using Oracle 9i Release 1.
I have a table "Attribution" with the following structure.


SQL> Desc attribution
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 REPORT_ID                                          NUMBER
 LABEL                                              VARCHAR2(20)
 VALUE                                              NUMBER(25,10)
 COLOR                                              VARCHAR2(10)

The inserted values in this table are:


SQL> select * from attribution;

 REPORT_ID LABEL                     VALUE COLOR
---------- -------------------- ---------- ----------
        24 Allocation           .025172879 996699
        24 Selection            -.03198432 FF9933
        24 Timing               .000016592 8B5A13
        24 Interaction           -.0148997 99583D
        24 Derivative Effect    -.00026146 CDCD00
        24 Active Return        -.02195601 638B45
        24 Active Risk          .031745116 800000

I want to generate an xml without the XML declaration row i.e. <?xml version="1.0"?>

Also I do not want the <Rowset> tags in my xml.

My generated XML should be like:

<set label="Allocation" value="0.4649000000" color="996699"/>
<set label="Selection" value="-4.3508000000" color="FF9933"/>
<set label="Timing" value="-0.0022000000" color="8B5A13"/>
<set label="Interaction" value="-0.4669000000" color="99583D"/>
<set label="Derivative Effect" value="-0.0184000000" color="CDCD00"/>
<set label="Active Return" value="-4.3733000000" color="638B45"/>
<set label="Active Risk" value="1.9901704500" color="800000"/>

where the value attribute should be equal to values*100.

Please help me in generating this xml. 

Thanks in Advance


kumar, May 09, 2011 - 6:27 am UTC

Hi tom,

can I create view in side procedure using dynamic sql. and also i want to pass input as a typ id in side view. and out put is xml format . result will display as per the user's input.

I am creating type as per requirement then trying to create view in side procedure passing input parameter. while i am running i am getting error "ORA-00905: missing keyword
ORA-06512: at "TFO_USER.GET_AVAIL_SELCTNLIST_XMLTEST", line 24
ORA-06512: at line 7"

or any other way to generate output in xml format as per user's input.

thanks
kumar
Tom Kyte
May 09, 2011 - 8:57 am UTC

why in the world would you create a view????? why wouldn't you just return a ref cursor?

and without code, we cannot debug your error.

and to debug your error, we need as LITTLE CODE AS HUMANLY POSSIBLE.

xml tags '<' , '>' are exchanged with &lt &gt

A reader, January 24, 2014 - 1:17 pm UTC

Tom,

after datapump export / import from 10g into 11g database we see that in very small subset of tables with xmltype columns (we have more than 100 such columns, but only about 10 are affected) xml tags '<' , '>' were replaced by &lt &gt.

Do you have any explanation for this?

More to Explore

CLOB/BLOB/etc

Complete documentation on Securefiles and Large Objects here