Extracting value from xml clob with Namespace using Oracle pl/sql

血红的双手。 提交于 2019-12-25 11:50:28

问题


I am currently trying to extract value from the clob column but always getting the result as null.

I tried out many possible scenarios but for me it is always returning as null.

Attached is the actual xml

<TenderOffer xmlns="http://xmlns.oracle.com/apps/otm">
    <Shipment>
        <ShipmentHeader/>
        <SEquipment/>
        <ShipmentStop/>
        <ShipmentStop/>
        <Location/>
        <Location/>
        <Release/>
        <RATE_OFFERING>
            <RATE_OFFERING_ROW>
                <USER_CLASSIFICATION3>ZXF</USER_CLASSIFICATION3>
            </RATE_OFFERING_ROW>
        </RATE_OFFERING>
    </Shipment>
    </TenderOffer>

and below is the actual query,

select 
        itc.element_name,
        extractvalue(XMLTYPE(XML_BLOB), '/TenderOffer/Shipment/RATE_OFFERING/RATE_OFFERING_ROW/USER_CLASSIFICATION3/text()'),
    XMLTYPE(XML_BLOB)
        from i_transaction itc
        where itc.i_transaction_no = 31553115
            and rownum = 1

回答1:


Your updated XML has a namespace, which finally reveals the issue. You need to specify the namespace as part of the XML extraction, which is simpler with the XMLTable approach; in this case you can just treat it as the default namespace:

select itc.element_name, x.user_classification3
from i_transaction itc
cross join xmltable(
  xmlnamespaces(default 'http://xmlns.oracle.com/apps/otm'),
    '/TenderOffer/Shipment/RATE_OFFERING/RATE_OFFERING_ROW'
  passing xmltype(itc.xml_blob)
  columns user_classification3 varchar2(10) path 'USER_CLASSIFICATION3'
) x
where itc.i_transaction_no = 31553115
and rownum = 1;

ELEMENT_NA USER_CLASS
---------- ----------
dummy      ZXF       

or with XMLQuery:

select itc.element_name, xmlquery(
  'declare default element namespace "http://xmlns.oracle.com/apps/otm"; (: :)
    /TenderOffer/Shipment/RATE_OFFERING/RATE_OFFERING_ROW/USER_CLASSIFICATION3/text()'
  passing xmltype(itc.xml_blob)
  returning content
) x
from i_transaction itc
where itc.i_transaction_no = 31553115
and rownum = 1;

ELEMENT_NA X                                                                               
---------- --------------------------------------------------------------------------------
dummy      ZXF                                                                             

If you wanted to keep using the deprecated extractvalue() function you can supply the namespace as an argument to that too, again as shown in the documentation:

select itc.element_name,
  extractvalue(xmltype(xml_blob),
    '/TenderOffer/Shipment/RATE_OFFERING/RATE_OFFERING_ROW/USER_CLASSIFICATION3/text()',
    'xmlns="http://xmlns.oracle.com/apps/otm"')
from i_transaction itc where itc.i_transaction_no = 31553115 and rownum = 1;



回答2:


In your code you use XML_BLOB as the variable - so I assumed a BLOB data type, which needs converting to a CLOB. However, if you have a CLOB value then you can skip using the BLOB_TO_CLOB function:

Oracle 11 Setup:

CREATE OR REPLACE FUNCTION BLOB_TO_CLOB( b BLOB )
RETURN CLOB 
IS
  c            CLOB;
  n            INTEGER     := 1;
  w   CONSTANT PLS_INTEGER := 32767;
  len CONSTANT INTEGER     := LENGTH( b );
BEGIN
  IF b IS NULL THEN
    RETURN NULL;
  END IF;

  IF len = 0 THEN
    RETURN EMPTY_CLOB();
  END IF;

  DBMS_LOB.CREATETEMPORARY( c, TRUE );
  WHILE ( n + w <= len ) LOOP
    DBMS_LOB.WRITEAPPEND( c, w, UTL_RAW.CAST_TO_VARCHAR2( DBMS_LOB.SUBSTR( b, w, n ) ) );
    n := n + w;
  END LOOP;
  DBMS_LOB.WRITEAPPEND( c, len - n + 1, UTL_RAW.CAST_TO_VARCHAR2( DBMS_LOB.SUBSTR( b, len - n + 1, n ) ) );
  RETURN c;
END;
/

CREATE TABLE blob_test ( value BLOB );

INSERT INTO blob_test VALUES (
  UTL_RAW.CAST_TO_RAW(
    '<Header>' ||
      '<SecondHeader>' ||
        '<ThirdHeader>' ||
          '<FourthHeader>' ||
            '<Value1>abcd</Value1>' ||
            '<Value2>xyz</Value2>' ||
            '<Value3>abxy</Value3>' ||
          '</FourthHeader>' ||
        '</ThirdHeader>' ||
      '</SecondHeader>' ||
    '</Header>'
  )
);

Query:

EXTRACT and EXTRACTVALUE are deprecated - use XMLTABLE instead:

SELECT Value1, Value2, Value3
FROM   blob_test b
       CROSS JOIN
       XMLTABLE(
         '/Header/SecondHeader/ThirdHeader/FourthHeader'
         PASSING XMLTYPE( BLOB_TO_CLOB( b.value ) )
         COLUMNS Value1 VARCHAR2(50) PATH 'Value1/text()',
                 Value2 VARCHAR2(50) PATH 'Value2/text()',
                 Value3 VARCHAR2(50) PATH 'Value3/text()'
       ) x;

Output:

VALUE1 VALUE2 VALUE3
------ ------ ------
abcd   xyz    abxy

Query 2:

If you do want to use EXTRACTVALUE you can remove the /text() from the XPath as EXTRACTVALUE will do that for you (but it should still work with it there too) and convert the BLOB to a CLOB:

SELECT EXTRACTVALUE(
         XMLTYPE( BLOB_TO_CLOB( value ) ), 
         '/Header/SecondHeader/ThirdHeader/FourthHeader/Value3'
       )
FROM   blob_test

Query - Update:

Simplification from @AlexPoole. The call to BLOB_TO_CLOB is not necessary as the XMLTYPE constructor can take a BLOB and a character set id:

SELECT Value1, Value2, Value3
FROM   blob_test b
       CROSS JOIN
       XMLTABLE(
         '/Header/SecondHeader/ThirdHeader/FourthHeader'
         PASSING XMLTYPE( b.value, NLS_CHARSET_ID('UTF8') )
         COLUMNS Value1 VARCHAR2(50) PATH 'Value1/text()',
                 Value2 VARCHAR2(50) PATH 'Value2/text()',
                 Value3 VARCHAR2(50) PATH 'Value3/text()'
       ) x;


来源:https://stackoverflow.com/questions/44515569/extracting-value-from-xml-clob-with-namespace-using-oracle-pl-sql

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!