Skip to Main Content
  • Questions
  • Convert XML to Object with non-existing field

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Roman.

Asked: November 13, 2019 - 9:28 am UTC

Last updated: November 28, 2019 - 11:26 am UTC

Version: 11.2.0.4.0

Viewed 1000+ times

You Asked

Hi, TOM!

Here's my preset:
SQL> create or replace type my_type force is object(
  2    id number,
  3    val varchar2(4000)
  4  )
  5  /
Type created
SQL> set serveroutput on size 999999
SQL> begin
  2    dbms_output.put_line(xmltype(my_type(1, 'VAL')).getstringval);
  3  end;
  4  /
<MY_TYPE><ID>1</ID><VAL>VAL</VAL></MY_TYPE>
PL/SQL procedure successfully completed


Then I try to convert XML to object:

SQL> declare
  2    l_val my_type;
  3  begin
  4    xmltype('<MY_TYPE><ID>1</ID><VAL>VAL</VAL></MY_TYPE>').toobject(l_val);
  5    dbms_output.put_line('l_val.id = ' || l_val.id);
  6    dbms_output.put_line('l_val.id = ' || l_val.val);
  7  end;
  8  /
l_val.id = 1
l_val.id = VAL
PL/SQL procedure successfully completed


Okay, it works well. Then assume that we got corrupted data where tag VAL doesn't exist:

SQL> declare
  2    l_val my_type;
  3  begin
  4    xmltype('<MY_TYPE><ID>1</ID></MY_TYPE>').toobject(l_val);
  5    dbms_output.put_line('l_val.id = ' || l_val.id);
  6    dbms_output.put_line('l_val.id = ' || l_val.val);
  7  end;
  8  /
l_val.id = 1
l_val.id = 
PL/SQL procedure successfully completed


Well, it works fine, we just have our VAL null. Then again we get corrupted data with extra tag FAIL_ATTR:

SQL> declare
  2    l_val my_type;
  3  begin
  4    xmltype('<MY_TYPE><ID>1</ID><VAL>VAL</VAL><FAIL_ATTR>YOU FAIL</FAIL_ATTR></MY_TYPE>').toobject(l_val);
  5    dbms_output.put_line('l_val.id = ' || l_val.id);
  6    dbms_output.put_line('l_val.id = ' || l_val.val);
  7  end;
  8  /
declare
  l_val my_type;
begin
  xmltype('<MY_TYPE><ID>1</ID><VAL>VAL</VAL><FAIL_ATTR>YOU FAIL</FAIL_ATTR></MY_TYPE>').toobject(l_val);
  dbms_output.put_line('l_val.id = ' || l_val.id);
  dbms_output.put_line('l_val.id = ' || l_val.val);
end;
ORA-19031: Элемент или атрибут XML FAIL_ATTR не имеет соответствия в типе IBS.MY_TYPE
ORA-06512: на  "SYS.XMLTYPE", line 196
ORA-06512: на  line 4


It fails!

So here's my question: can I somehow force Oracle to skip such attributes that aren't declared in a type specification? For me it would be okay to miss them.

and Chris said...

I've checked with the XML team - sadly there is no way to force skip the extra attributes.

You'll have to build your own solution to do the mapping.

Or create a type with the extra elements ;)

Rating

  (1 rating)

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

Comments

XSLT to removed unwanted nodes

Mark Wooldridge, November 27, 2019 - 4:35 pm UTC

You use xslt to remove any node that does not match what is your object. The unwanted xml could be inserted into an error table for further review/processing.

Not sure if the syntax is correct but something like the following:

<xsl:template match="ID|VAL">
  <xsl:copy>
    <xsl:apply-templates select="ID|VAL"/>
  </xsl:copy>
</xsl:template>

Chris Saxon
November 28, 2019 - 11:26 am UTC

Nice idea

More to Explore

SQL

The Oracle documentation contains a complete SQL reference.