使用 Oracle pl/sql 从具有命名空间的 xml clob 中提取值
Extracting value from xml clob with Namespace using Oracle pl/sql
我目前正在尝试从 clob
列中提取值,但得到的结果总是 null
。
我尝试了很多可能的场景,但对我来说它总是返回 null
。
附上实物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>
以下是实际查询,
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
在您的代码中,您使用 XML_BLOB
作为变量 - 所以我假设了 BLOB
数据类型,需要转换为 CLOB
。但是,如果您有一个 CLOB
值,那么您可以跳过使用 BLOB_TO_CLOB
函数:
Oracle 11 设置:
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>'
)
);
查询:
EXTRACT
和 EXTRACTVALUE
已弃用 - 请改用 XMLTABLE
:
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;
输出:
VALUE1 VALUE2 VALUE3
------ ------ ------
abcd xyz abxy
查询 2:
如果您确实想使用 EXTRACTVALUE
,您可以从 XPath 中删除 /text()
,因为 EXTRACTVALUE
会为您完成(但它仍然可以在那里使用)并将 BLOB
转换为 CLOB
:
SELECT EXTRACTVALUE(
XMLTYPE( BLOB_TO_CLOB( value ) ),
'/Header/SecondHeader/ThirdHeader/FourthHeader/Value3'
)
FROM blob_test
查询 - 更新:
@AlexPoole. The call to BLOB_TO_CLOB
is not necessary as the XMLTYPE
constructor 的简化可以采用 BLOB
和字符集 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;
您更新后的 XML 有一个命名空间,这最终揭示了问题。您需要 specify the namespace as part of the XML extraction,使用 XMLTable 方法更简单;在这种情况下,您可以将其视为默认命名空间:
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
或使用XML查询:
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
如果您想继续使用已弃用的 extractvalue()
函数,您也可以再次将命名空间作为参数提供给它 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;
我目前正在尝试从 clob
列中提取值,但得到的结果总是 null
。
我尝试了很多可能的场景,但对我来说它总是返回 null
。
附上实物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>
以下是实际查询,
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
在您的代码中,您使用 XML_BLOB
作为变量 - 所以我假设了 BLOB
数据类型,需要转换为 CLOB
。但是,如果您有一个 CLOB
值,那么您可以跳过使用 BLOB_TO_CLOB
函数:
Oracle 11 设置:
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>'
)
);
查询:
EXTRACT
和 EXTRACTVALUE
已弃用 - 请改用 XMLTABLE
:
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;
输出:
VALUE1 VALUE2 VALUE3
------ ------ ------
abcd xyz abxy
查询 2:
如果您确实想使用 EXTRACTVALUE
,您可以从 XPath 中删除 /text()
,因为 EXTRACTVALUE
会为您完成(但它仍然可以在那里使用)并将 BLOB
转换为 CLOB
:
SELECT EXTRACTVALUE(
XMLTYPE( BLOB_TO_CLOB( value ) ),
'/Header/SecondHeader/ThirdHeader/FourthHeader/Value3'
)
FROM blob_test
查询 - 更新:
@AlexPoole. The call to BLOB_TO_CLOB
is not necessary as the XMLTYPE
constructor 的简化可以采用 BLOB
和字符集 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;
您更新后的 XML 有一个命名空间,这最终揭示了问题。您需要 specify the namespace as part of the XML extraction,使用 XMLTable 方法更简单;在这种情况下,您可以将其视为默认命名空间:
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
或使用XML查询:
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
如果您想继续使用已弃用的 extractvalue()
函数,您也可以再次将命名空间作为参数提供给它 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;