How to validate XML file in Oracle PLSQL - sql

My XML file looks below format
<?xml version = '1.0'?>
<ROWSET>
<ROW>
<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>
<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>
<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 -- Now corresponding closing tag is missed in this line
</ROWSET>
Now My corresponding closing tag was missed in any of the nodes. In PLSQL programming how can identify the missing tag? XMLDB option I can use,But I would like do it in PLSQL.

If you only need to check if it is a valid XML, you can simply try converting it, handlng the error; for example:
good xml:
SQL> select xmltype(q'[<?xml version = '1.0'?>
2 <ROWSET>
3 <ROW>
4 <EMPNO>7369</EMPNO>
5 </ROW>
6 </ROWSET>]')
7 from dual;
XMLTYPE(Q'[<?XMLVERSION='1.0'?><ROWSET><ROW><EMPNO>7369</EMPNO></ROW></ROWSET>]'
--------------------------------------------------------------------------------
<?xml version="1.0"?>
<ROWSET>
<ROW>
<EMPNO>7369</EMPNO>
</ROW>
</ROWSET
bad xml:
SQL> select xmltype(q'[<?xml version = '1.0'?>
2 <ROWSET>
3 <ROW>
4 <EMPNO>7369</EMPNO>
5 </ROW
6 </ROWSET>]')
7 from dual;
ERROR:
ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00231: invalid character 60 ('<') found in a Name or Nmtoken
Error at line 6
ORA-06512: at "SYS.XMLTYPE", line 310
ORA-06512: at line 1

Related

How to extract only the subtag in this xml element

with this query I can select the content of tag
select xmltype(
'<?xml version="1.0"?>
<ROWSET>
<ROW>
<PERSON_NUMBER>1000142</PERSON_NUMBER>
<LOAN_1>25000</LOAN_1>
</ROW>
<ROW>
<PERSON_NUMBER>1000142</PERSON_NUMBER>
<LOAN_1>25000</LOAN_1>
</ROW>
</ROWSET>'
).extract( '/ROWSET/ROW' ) .getstringval() p#
from dual;
<PERSON_NUMBER>1000142</PERSON_NUMBER><LOAN_1>25000</LOAN_1><PERSON_NUMBER>1000142</PERSON_NUMBER><LOAN_1>25000</LOAN_1>
but what I want is to have a list of the sub-tag.
the expected result for this example would be:
PERSON_NUMBER, LOAN_1
code
Similar to an answer to your previous question, you can get the name() XPATH value:
SELECT DISTINCT name
from XMLTABLE(
'/ROWSET/ROW/*'
PASSING xmltype(
'<?xml version="1.0"?>
<ROWSET>
<ROW>
<PERSON_NUMBER>1000142</PERSON_NUMBER>
<LOAN_1>25000</LOAN_1>
<LOAN_2>26000</LOAN_2>
</ROW>
<ROW>
<PERSON_NUMBER>1000142</PERSON_NUMBER>
<LOAN_1>25000</LOAN_1>
<LOAN_2>26000</LOAN_2>
</ROW>
</ROWSET>'
)
COLUMNS
name VARCHAR2(200) PATH './name()'
);
Outputs:
NAME
PERSON_NUMBER
LOAN_1
LOAN_2
db<>fiddle here

oracle XML to Database table

I have XML like this . I am unable to parse it into a table
<REQMST>
<ROW>
<REQ_ID>668 </REQ_ID>
<RequestDetails>
<REQ_DTL_ID>845</REQ_DTL_ID>
<INTERFACE_REFNUM>1</INTERFACE_REFNUM>
</RequestDetails>
<RequestDetails>
<REQ_DTL_ID>846</REQ_DTL_ID>
<INTERFACE_REFNUM>2</INTERFACE_REFNUM>
</RequestDetails>
</ROW>
</REQMST>
I am trying to parse it into table using
select *
FROM XMLTABLE('/REQMST/ROW'
PASSING
xmltype('
<REQMST>
<ROW>
<REQ_ID>668 </REQ_ID>
<RequestDetails>
<REQ_DTL_ID>845</REQ_DTL_ID>
<INTERFACE_REFNUM>1</INTERFACE_REFNUM>
</RequestDetails>
<RequestDetails>
<REQ_DTL_ID>846</REQ_DTL_ID>
<INTERFACE_REFNUM>2</INTERFACE_REFNUM>
</RequestDetails>
</ROW>
</REQMST>')
COLUMNS
--describe columns and path to them:
REQ_ID varchar2(20) PATH './REQ_ID',
REQ_DTL_ID varchar2(20) PATH './RequestDetails/REQ_DTL_ID',
INTERFACE_REFNUM varchar2(20) PATH './RequestDetails/INTERFACE_REFNUM'
) xmlt
;
I am getting error ORA-19279: XPTY0004 - XQuery dynamic type mismatch: expected singleton sequence - got multi-item sequence
it works if there is only one RequestDetails
You need to go one more level down to get the details from RequestDetails tag using the same technique as parent.
Used column name xml to get the xml as xmltype column and then use xmltable on it to get the further details:
Try this:
select xmlt.req_id, x.REQ_DTL_ID, x.INTERFACE_REFNUM
FROM XMLTABLE('/REQMST/ROW'
PASSING
xmltype('
<REQMST>
<ROW>
<REQ_ID>668 </REQ_ID>
<RequestDetails>
<REQ_DTL_ID>845</REQ_DTL_ID>
<INTERFACE_REFNUM>1</INTERFACE_REFNUM>
</RequestDetails>
<RequestDetails>
<REQ_DTL_ID>846</REQ_DTL_ID>
<INTERFACE_REFNUM>2</INTERFACE_REFNUM>
</RequestDetails>
</ROW>
</REQMST>')
COLUMNS
--describe columns and path to them:
REQ_ID varchar2(20) PATH 'REQ_ID',
xml xmltype PATH 'RequestDetails'
) xmlt, xmltable('/RequestDetails'
passing xmlt.xml
columns
REQ_DTL_ID varchar2(20) PATH 'REQ_DTL_ID',
INTERFACE_REFNUM varchar2(20) PATH 'INTERFACE_REFNUM'
) x;
Produces:
REQ_ID REQ_DTL_ID INTERFACE_REFNUM
668 845 1
668 846 2

Replace or remove mutliple lines of text in oracle stored procedure

Could any one help me to repalce or remove set of lines using a replace or regex replace function,and what would be the string pattern to find and replace
lines to be replaced from below text
</properties>
<?xml version="1.0"?>
<properties>
Text
<COLLECT_PARALLELGRAMMAR1>global.grxml</COLLECT_PARALLELGRAMMAR1>
<COLLECT_INPUTMODES>voice dtmf</COLLECT_INPUTMODES>
<CONF_INPUTMODES>dtmf</CONF_INPUTMODES>
</ROW>
</properties>
<?xml version="1.0"?>
<properties>
<ROW>
<MODULE_NAME>main_menu_phone</MODULE_NAME>
<MODULE_DESCRIPTION>Main Menu for Customers with silver membership</MODULE_DESCRIPTION>
<MODULE_TYPE>phone</MODULE_TYPE>
If it is plain text and not XML, then you could simply use REPLACE.
For example,
SQL> WITH DATA AS
2 (SELECT '
3 <COLLECT_PARALLELGRAMMAR1>global.grxml</COLLECT_PARALLELGRAMMAR1>
4 <COLLECT_INPUTMODES>voice dtmf</COLLECT_INPUTMODES>
5 <CONF_INPUTMODES>dtmf</CONF_INPUTMODES>
6 </ROW>
7 </properties>
8 <?xml version="1.0"?>
9 <properties>
10 <ROW>
11 <MODULE_NAME>main_menu_phone</MODULE_NAME>
12 <MODULE_DESCRIPTION>Main Menu for Customers with silver membership</MODULE_DESCRIPTION>
13 <MODULE_TYPE>phone</MODULE_TYPE>' str
14 FROM dual
15 )
16 SELECT REPLACE(str, '</properties>
17 <?xml version="1.0"?>
18 <properties>', '') new_str
19 FROM data;
NEW_STR
--------------------------------------------------------------------------------------------
<COLLECT_PARALLELGRAMMAR1>global.grxml</COLLECT_PARALLELGRAMMAR1>
<COLLECT_INPUTMODES>voice dtmf</COLLECT_INPUTMODES>
<CONF_INPUTMODES>dtmf</CONF_INPUTMODES>
</ROW>
<ROW>
<MODULE_NAME>main_menu_phone</MODULE_NAME>
<MODULE_DESCRIPTION>Main Menu for Customers with silver membership</MODULE_DESCRIPTION>
<MODULE_TYPE>phone</MODULE_TYPE>

Extract xml data using oracle query

Oracle version 11g
HI ,
When trying to read the XML in a LOOP the query is giving an error but if, I change this to a non existing path then the query is running fine . However the #Name is not fetching is the expected . What should I correct here to make it give the desired output given below:
sqlfiddle link
Non exsisting path described above, removed the E from the name : for $i in AuxiliaryObject/Row return <C>{$i}<R>{AuxiliaryObject/#NAM}
code :
SELECT *
FROM XMLTABLE (
'<C> {for $i in AuxiliaryObject/Row return <C>{$i}<R>{AuxiliaryObject/#NAM}</R></C>}</C>/C'
PASSING xmltype(
'<AuxiliaryType>
<AuxiliaryObject id="1" NAME="Provider_P107">
<Row>
<Index_id>1</Index_id>
<Provider_ID_description>GNRCN</Provider_ID_description>
<Provider_ID>GNRCN</Provider_ID>
</Row>
<Row>
<Index_id>2</Index_id>
<Provider_ID_description>EGUT12</Provider_ID_description>
<Provider_ID>EGUT12 </Provider_ID>
</Row>
</AuxiliaryObject>
<AuxiliaryObject id="2" NAME="Provider_P108">
<Row>
<Index_id>1</Index_id>
<Provider_ID_description>GNRCN</Provider_ID_description>
<Provider_ID>GNRCN</Provider_ID>
</Row>
<Row>
<Index_id>2</Index_id>
<Provider_ID_description>EGUT</Provider_ID_description>
<Provider_ID>EGUT </Provider_ID>
</Row>
</AuxiliaryObject>
</AuxiliaryType>'
).EXTRACT ('AuxiliaryType/*')
COLUMNS
Name varchar (30) Path 'R/#NAME',
Index_Id VARCHAR2 (10) PATH 'Row/Index_id',
Provider_id_description VARCHAR2 (30) PATH 'Row/Provider_ID_description',
provider_id VARCHAR2 (30) PATH 'Row/Provider_ID')
Output : Desired :
ID, Provider_Name, Index, Provider_ID_description, Provider_ID
1 Provider_P107 1 GNRCN GNRCN
1 Provider_P107 2 INDF1 INDF1
2 Provider_P108 2 EGUT12 EGUT12
2 Provider_P108 1 EGUT EGUT
Output coming is in the sqlfiddle link.
The above Queation is a link to this :
Extract data from a XML and load it into a table
When I run the query on Toad : Output is :
NAME INDEX_ID PROVIDER_ID_DESCRIPTION PROVIDER_ID
Provider_P107Provider_P108 1 GNRCN GNRCN
Provider_P107Provider_P108 2 EGUT12 EGUT12
Provider_P107Provider_P108 1 GNRCN GNRCN
Provider_P107Provider_P108 2 EGUT EGUT
I would extract the data in stages:
SELECT xobjects.id, xobjects.name, xrows.index_id,
xrows.provider_id_description, xrows.provider_id
FROM XMLTABLE(
'/AuxiliaryType/AuxiliaryObject'
PASSING xmltype(
'<AuxiliaryType>
<AuxiliaryObject id="1" NAME="Provider_P107">
<Row>
<Index_id>1</Index_id>
<Provider_ID_description>GNRCN</Provider_ID_description>
<Provider_ID>GNRCN</Provider_ID>
</Row>
<Row>
<Index_id>2</Index_id>
<Provider_ID_description>EGUT12</Provider_ID_description>
<Provider_ID>EGUT12 </Provider_ID>
</Row>
</AuxiliaryObject>
<AuxiliaryObject id="2" NAME="Provider_P108">
<Row>
<Index_id>1</Index_id>
<Provider_ID_description>GNRCN</Provider_ID_description>
<Provider_ID>GNRCN</Provider_ID>
</Row>
<Row>
<Index_id>2</Index_id>
<Provider_ID_description>EGUT</Provider_ID_description>
<Provider_ID>EGUT </Provider_ID>
</Row>
</AuxiliaryObject>
</AuxiliaryType>'
)
COLUMNS
name VARCHAR2(30) PATH '#NAME',
id VARCHAR2(10) PATH '#id',
xrows XMLTYPE PATH 'Row') xobjects,
XMLTABLE(
'/Row'
PASSING xobjects.xrows
COLUMNS
index_id VARCHAR2(10) PATH 'Index_id',
provider_id_description VARCHAR2(30) PATH 'Provider_ID_description',
provider_id VARCHAR2(30) PATH 'Provider_ID') xrows;
The XMLTable xobjects contains each of the AuxiliaryObject instances within the AuxiliaryType, from your original XML text. It has the attributes name and id, plus a sub-XMLType containing the nested rows. The second XMLTable, xrows, expands that so the elements can be extracted. The joins and passing of the XML types creates the hierarchy that gives the output you want:
ID NAME INDEX_ID PROVIDER_ID_DESCRIPTION PROVIDER_ID
---------- ------------------------------ ---------- ------------------------------ ------------------------------
1 Provider_P107 1 GNRCN GNRCN
1 Provider_P107 2 EGUT12 EGUT12
2 Provider_P108 1 GNRCN GNRCN
2 Provider_P108 2 EGUT EGUT
This works in SQL Developer against an 11.2.0.3 database, and in SQL Fiddle.
An earlier CTE-based version of this answer also worked in SQL Developer but SQL Fiddle got an ORA-600 error; that along with the issue you had in the question suggests maybe SQL Fiddle is on an unpatched, or at least differently patched, version of 11gR2 which has bugs in the XML handling.

Can I alias columns from a cursor in SELECT statement in Oracle?

I am writing a client application that calls a stored procedure from an Oracle database via a select statement. The stored procedure returns a cursor. I need to define aliases for the columns returned by this cursor, and I need to do it within my select statement.
I cannot make any changes to the Oracle database. I cannot write any PLSQL. The only thing I can do with this database is query it.
Please advise.
Background: This stored procedure is one of many called inside an application framework. Currently, all calls return their results in XML format, using this syntax to do the conversion:
select XMLType.createXML(package_name.storedProcName('1', '2', '3')).getClobVal() as sresult from dual;
However, this cursor contains two columns with the same name (specifically "NAME"). When this query is run in TOAD, the column automatically gets appended a "_1", however the XMLType results in illogical XML, like this:
<?xml version="1.0"?>
<ROWSET>
<ROW>
<ID>1</ID>
<NAME>BRUCE WAYNE</NAME>
<NAME>BATMAN</NAME>
</ROW>
</ROWSET>
This is why I must alias the columns before they are converted to XMLType. I want the query output to contain no duplicate column names so that the XML can be like this instead (with no duplicate tags):
<?xml version="1.0"?>
<ROWSET>
<ROW>
<ID>1</ID>
<NAME>BRUCE WAYNE</NAME>
<OTHER_NAME>BATMAN</OTHER_NAME>
</ROW>
</ROWSET>
i would go for a stylesheet for this.
eg:
SQL> select XMLType.createXML(foo()).transform(xmltype('<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
2 <xsl:template match="/ROWSET/ROW/NAME[2]">
3 <NAME_1>
4 <xsl:apply-templates select="#*|node()"/>
5 </NAME_1>
6 </xsl:template>
7 <xsl:template match="#*|node()">
8 <xsl:copy>
9 <xsl:apply-templates select="#*|node()"/>
10 </xsl:copy>
11 </xsl:template>
12 </xsl:stylesheet>')) as sresult from dual
13 /
SRESULT
--------------------------------------------------------------------------------
<ROWSET>
<ROW>
<ID>1</ID>
<NAME>BRUCE WAYNE</NAME>
<NAME_1>BATMAN</NAME_1>
</ROW>
<ROW>
<ID>2</ID>
<NAME>CLARK KENT</NAME>
<NAME_1>SUPERMAN</NAME_1>
</ROW>
</ROWSET>
i.e. we replace the 2nd NAME occurrence (/ROWSET/ROW/NAME[2]) in the ROW element with NAME_1. everything else gets copied as-is.