我有这样的testing.xml文件:
<ROWSET>
<ROW_DATA:TYPE>
<ID>1</ID>
<TEXT>This is some text</TEXT>
</ROW_DATA:TYPE>
<ROW_DATA:TYPE>
<ID>2</ID>
<TEXT>This is some more text</TEXT>
</ROW_DATA:TYPE>
<ROW_DATA:TYPE>
<ID>3</ID>
<TEXT>This is some other text</TEXT>
</ROW_DATA:TYPE>
<ROW_DATA:TYPE>
<ID>4</ID>
<TEXT>This is also some text</TEXT>
</ROW_DATA:TYPE>
</ROWSET>
我将这个testing.xml文件加载到表test_xml:
中INSERT INTO test_xml VALUES(
xmltype(bfilename('TESTING','testing.xml'),nls_charset_id('AL32UTF8')));
commit;
之后,我尝试编写代码以从xml表中获取数据:
select grp1.*
from
test_xml t
,xmltable('//ROWSET'
passing t.SYS_NC_ROWINFO$
columns row_1 xmltype path '/ROWSET/ROW_DATA:TYPE'
) grp0
,xmltable('/ROW_DATA:TYPE'
passing grp0.row_1
columns ID_1 NUMBER(10) PATH 'ID'
,TEXT_1 VARCHAR2(40) PATH 'TEXT'
) grp1
;
最后,它出现了一条错误消息:
ORA-19228: XPST0008 - undeclared identifier: prefix 'ROW_DATA' local-name 'ROW_DATA:TYPE'
19228. 00000 - "XP0008 - undeclared identifier: prefix '%s' local-name '%s'"
*Cause: The given identifier refers to either a type name, function name, namespace prefix, or variable name that is not defined in the static context.
*Action: Fix the expression to remove the identifier, or declare the appropriate variable, type, function or namespace.
Error at Line: 17 Column: 2
因此,在其中一个XML节点中,它们具有我无法处理的特殊字符(:)。有人可以帮我吗?
Real XML文件(来自网络服务)是:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<MultiSpeakMsgHeader AppName="CD" AppVersion="3.0" CSUnits="feet" Company="xxxxx" LastSent="123455" ObjectsRemaining="1" xmlns="http://www.multispeak.org/Version_3.0"/>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<GetReadingsByDateResponse>
<GetReadingsByDateResult>
<meterRead>
<meterNo>10227</meterNo>
<deviceID>2</deviceID>
<readingDate>2016-12-18T06:15:00.339Z</readingDate>
<posKWh>85893</posKWh>
<kW>2.8018</kW>
<phase>AB</phase>
<readingValues>
<readingValue>
<units>kWh</units>
<value>85892.586</value>
<readingValueType>Energy</readingValueType>
<dateTime>2016-12-18T06:15:00.339Z</dateTime>
</readingValue>
<readingValue>
<units>kW</units>
<value>2.504</value>
<readingValueType>Current demand</readingValueType>
<dateTime>2016-12-18T06:15:00.339Z</dateTime>
</readingValue>
<readingValue>
<units>kW</units>
<value>2.8018</value>
<readingValueType>Max demand</readingValueType>
<dateTime>2016-12-18T06:15:00.339Z</dateTime>
</readingValue>
<readingValue>
<units>V</units>
<value>244.1</value>
<readingValueType>Current Voltage</readingValueType>
<dateTime>2016-12-18T06:15:00.339Z</dateTime>
</readingValue>
<readingValue>
<units>V</units>
<value>244.1</value>
<readingValueType>Current Voltage Phase A</readingValueType>
<dateTime>2016-12-18T06:15:00.339Z</dateTime>
</readingValue>
<readingValue>
<units>V</units>
<value>0.3</value>
<readingValueType>Current Voltage Phase B</readingValueType>
<dateTime>2016-12-18T06:15:00.339Z</dateTime>
</readingValue>
</readingValues>
</meterRead>
</GetReadingsByDateResult>
</GetReadingsByDateResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
答案 0 :(得分:1)
错误是因为您的查询未在XMLTable调用中声明命名空间。 XML具有在SOAP-ENV:Envelope
节点中声明的名称空间,xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
。
您可以向XMLTable调用添加名称空间声明,例如:
select grp1.*
from
test_xml t
,xmltable(xmlnamespaces ('http://schemas.xmlsoap.org/soap/envelope' AS "SOAP-ENV"),
'/SOAP-ENV:Envelope'
passing t.SYS_NC_ROWINFO$
columns row_1 xmltype path 'SOAP-ENV:Body'
) grp0
,xmltable(xmlnamespaces ('http://schemas.xmlsoap.org/soap/envelope' AS "SOAP-ENV"),
'/SOAP-ENV:Body'
passing grp0.row_1
columns ID_1 NUMBER(10) PATH 'ID'
,TEXT_1 VARCHAR2(40) PATH 'TEXT'
) grp1
或者您的示例数据更有用的示例:
select x1.meterNo,
from_tz(to_timestamp(x1.readingDate, 'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"'), 'UTC') as readingDate,
x2.readingValueType, x2.value, x2.units
from test_xml t
cross join xmltable(
xmlnamespaces ('http://schemas.xmlsoap.org/soap/envelope/' AS "SOAP-ENV"),
'/SOAP-ENV:Envelope/SOAP-ENV:Body/GetReadingsByDateResponse/GetReadingsByDateResult/meterRead'
passing t.SYS_NC_ROWINFO$
columns meterNo number path 'meterNo',
readingDate varchar2(24) path 'readingDate',
readingValues xmltype path 'readingValues'
) x1
cross join xmltable(
'/readingValues/readingValue'
passing x1.readingValues
columns readingValueType varchar2(30) path 'readingValueType',
value number path 'value',
units varchar2(3) path 'units'
) x2;
METERNO READINGDATE READINGVALUETYPE VALUE UNI
---------- -------------------------------- ------------------------------ ---------- ---
10227 18-DEC-16 06.15.00.339000000 UTC Energy 85892.586 kWh
10227 18-DEC-16 06.15.00.339000000 UTC Current demand 2.504 kW
10227 18-DEC-16 06.15.00.339000000 UTC Max demand 2.8018 kW
10227 18-DEC-16 06.15.00.339000000 UTC Current Voltage 244.1 V
10227 18-DEC-16 06.15.00.339000000 UTC Current Voltage Phase A 244.1 V
10227 18-DEC-16 06.15.00.339000000 UTC Current Voltage Phase B .3 V
请注意,在这种情况下,您不需要在第二个XMLTable中声明名称空间,因为您引用的节点没有SOAP-ENV前缀。
你可以欺骗并使用通配符:
...
from test_xml t
cross join xmltable(
'/*:Envelope/*:Body/GetReadingsByDateResponse/GetReadingsByDateResult/meterRead'
passing t.SYS_NC_ROWINFO$
...
或忽略带有前缀的节点,如果您不需要直接来自这些节点的数据,只有他们的孩子:
...
from test_xml t
cross join xmltable(
'//meterRead'
passing t.SYS_NC_ROWINFO$
...
但我认为明白这一点会更好。