使用 XMLTABLE 和 xquery 从 xml 中提取数据
Using XMLTABLE and xquery to extract data from xml
我有下面这一段XML:
<per:Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.something.com/2014/11/bla/webservice.xsd"
xmlns:per="http://www.something.com/2014/11/bla/person">
<per:Initials>E.C.</per:Initials>
<per:FirstName>Erik</per:FirstName>
<per:LastName>Flipsen</per:LastName>
<per:BirthDate>1980-07-01</per:BirthDate>
<per:Gender>Male</per:Gender>
</per:Person>
我想从这个 xml 中提取一些数据 PL/SQL。我想使用 XMLTABLE,因为 EXTRACT 和 EXTRACTVALUE 函数已被弃用。
我可以使用此查询提取数据:
select pers.Initials,
pers.Firstname
into lsInitials,
lsFirstname
from
XMLTABLE ('*:Person' passing pxRequest
columns Initials PATH '*:Initials',
Firstname PATH '*:FirstName'
) pers;
我对命名空间使用通配符,因为我真的不在乎发送方对命名空间使用什么缩写,无论如何我都知道获取数据的确切路径。
有了这段代码,有两件事让我感到困惑:
- 根据 http://docs.oracle.com/database/121/SQLRF/functions268.htm#SQLRF06232 上的文档,PATH 应该是可选的,但是,一旦我从 COLUMNS 部分删除 PATH,我就不会再得到任何结果。
编辑:
我发现当我删除元素的命名空间并将它们设为大写时,它就可以工作了。因此,列名似乎需要与 xml 元素名称匹配才能使其正常工作。我还没有弄清楚如何让它与命名空间 XML.
一起工作
- 文档还注明了 "For each resulting column except the FOR ORDINALITY column, you must specify the column data type",但是,没有它似乎也能正常工作。为列和我要将数据提取到的变量指定它似乎也有点多余。不知道如果不指定数据类型会给我带来麻烦吗?
可运行代码示例:
SET SERVEROUTPUT ON;
DECLARE
pxRequest xmltype := xmltype('<per:Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.something.com/2014/11/bla/webservice.xsd"
xmlns:per="http://www.something.com/2014/11/bla/person">
<per:Initials>E.C.</per:Initials>
<per:FirstName>Erik</per:FirstName>
<per:LastName>Flipsen</per:LastName>
<per:BirthDate>1980-01-01</per:BirthDate>
<per:Gender>Male</per:Gender>
</per:Person>');
lsInitials varchar2(100);
lsFirstname varchar2(100);
begin
select pers.Initials,
pers.Firstname
into lsInitials,
lsFirstname
from
XMLTABLE ('*:Person' passing pxRequest
columns Initials PATH '*:Initials',
Firstname PATH '*:FirstName'
) pers;
dbms_output.put_line(lsInitials);
dbms_output.put_line(lsFirstname);
end;
参考文献:
How to parse xml by xmltable when using namespace in xml(Oracle)
如果您在 xmltable 中加载命名空间元素,它应该会按预期工作:
select results
from xmltable(
xmlnamespaces(
default 'http://tempuri.org/',
'http://schemas.xmlsoap.org/soap/envelope/' as "soap"
),
'soap:Envelope/soap:Body/addResponse' passing xmltype(v_xml)
columns results varchar(100) path './addResult')
根据你的例子(你可能还需要提前注册你的schema/namespace,但那应该是一次):
select pers.Initials,
pers.Firstname
into lsInitials,
lsFirstname
from
XMLTABLE (
xmlnamespaces(
default 'http://tempuri.org/',
'http://www.w3.org/2001/XMLSchema-instance' as "xsi",
'http://www.something.com/2014/11/bla/person' as "per"
),
passing pxRequest
columns Initials PATH '*:Initials',
Firstname PATH '*:FirstName'
) pers;
关于 XML,以前版本的 Oracle 中可以使用的东西在 11g+ 中不起作用,据我所见,Oracle 强烈 verifies/types input/output XML 操作,在以前的版本中,您可以 运行 在没有命名空间信息的情况下正常进行正确的 XQuery 操作。
根据你的第一个问题,the documentation you linked 今天有关于省略 PATH
:
The optional PATH
clause specifies that the portion of the XQuery result that is addressed by XQuery expression string is to be used as the column content.
If you omit PATH
, then the XQuery expression column is assumed. For example:
(... COLUMNS xyz)
is equivalent to
XMLTable(... COLUMNS xyz PATH 'XYZ')
You can use different PATH clauses to split the XQuery result into different virtual-table columns.
列 xyz
被假定为 'XYZ'
的原因是因为 Oracle 默认情况下不区分大小写(默认为全部大写)。如果您将列定义为 "aBcD"
,则 PATH
值将假定为 'aBcD'
关于您关于指定数据类型的第二个问题:如果您要提取的数据始终是文本数据,您或许可以不指定数据类型。
但是,如果您开始处理日期、时间戳、浮点数等内容,那么您可能 运行 会遇到问题。您需要使用 TO_*
函数手动转换它们,或者您可以在列定义中指定它们的数据类型。如果您不这样做,Oracle 可以自由地隐式转换它,但它感觉合适,这可能会产生意想不到的后果。
我有下面这一段XML:
<per:Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.something.com/2014/11/bla/webservice.xsd"
xmlns:per="http://www.something.com/2014/11/bla/person">
<per:Initials>E.C.</per:Initials>
<per:FirstName>Erik</per:FirstName>
<per:LastName>Flipsen</per:LastName>
<per:BirthDate>1980-07-01</per:BirthDate>
<per:Gender>Male</per:Gender>
</per:Person>
我想从这个 xml 中提取一些数据 PL/SQL。我想使用 XMLTABLE,因为 EXTRACT 和 EXTRACTVALUE 函数已被弃用。
我可以使用此查询提取数据:
select pers.Initials,
pers.Firstname
into lsInitials,
lsFirstname
from
XMLTABLE ('*:Person' passing pxRequest
columns Initials PATH '*:Initials',
Firstname PATH '*:FirstName'
) pers;
我对命名空间使用通配符,因为我真的不在乎发送方对命名空间使用什么缩写,无论如何我都知道获取数据的确切路径。
有了这段代码,有两件事让我感到困惑:
- 根据 http://docs.oracle.com/database/121/SQLRF/functions268.htm#SQLRF06232 上的文档,PATH 应该是可选的,但是,一旦我从 COLUMNS 部分删除 PATH,我就不会再得到任何结果。
编辑:
我发现当我删除元素的命名空间并将它们设为大写时,它就可以工作了。因此,列名似乎需要与 xml 元素名称匹配才能使其正常工作。我还没有弄清楚如何让它与命名空间 XML.
一起工作- 文档还注明了 "For each resulting column except the FOR ORDINALITY column, you must specify the column data type",但是,没有它似乎也能正常工作。为列和我要将数据提取到的变量指定它似乎也有点多余。不知道如果不指定数据类型会给我带来麻烦吗?
可运行代码示例:
SET SERVEROUTPUT ON;
DECLARE
pxRequest xmltype := xmltype('<per:Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.something.com/2014/11/bla/webservice.xsd"
xmlns:per="http://www.something.com/2014/11/bla/person">
<per:Initials>E.C.</per:Initials>
<per:FirstName>Erik</per:FirstName>
<per:LastName>Flipsen</per:LastName>
<per:BirthDate>1980-01-01</per:BirthDate>
<per:Gender>Male</per:Gender>
</per:Person>');
lsInitials varchar2(100);
lsFirstname varchar2(100);
begin
select pers.Initials,
pers.Firstname
into lsInitials,
lsFirstname
from
XMLTABLE ('*:Person' passing pxRequest
columns Initials PATH '*:Initials',
Firstname PATH '*:FirstName'
) pers;
dbms_output.put_line(lsInitials);
dbms_output.put_line(lsFirstname);
end;
参考文献:
How to parse xml by xmltable when using namespace in xml(Oracle)
如果您在 xmltable 中加载命名空间元素,它应该会按预期工作:
select results
from xmltable(
xmlnamespaces(
default 'http://tempuri.org/',
'http://schemas.xmlsoap.org/soap/envelope/' as "soap"
),
'soap:Envelope/soap:Body/addResponse' passing xmltype(v_xml)
columns results varchar(100) path './addResult')
根据你的例子(你可能还需要提前注册你的schema/namespace,但那应该是一次):
select pers.Initials,
pers.Firstname
into lsInitials,
lsFirstname
from
XMLTABLE (
xmlnamespaces(
default 'http://tempuri.org/',
'http://www.w3.org/2001/XMLSchema-instance' as "xsi",
'http://www.something.com/2014/11/bla/person' as "per"
),
passing pxRequest
columns Initials PATH '*:Initials',
Firstname PATH '*:FirstName'
) pers;
关于 XML,以前版本的 Oracle 中可以使用的东西在 11g+ 中不起作用,据我所见,Oracle 强烈 verifies/types input/output XML 操作,在以前的版本中,您可以 运行 在没有命名空间信息的情况下正常进行正确的 XQuery 操作。
根据你的第一个问题,the documentation you linked 今天有关于省略 PATH
:
The optional
PATH
clause specifies that the portion of the XQuery result that is addressed by XQuery expression string is to be used as the column content.If you omit
PATH
, then the XQuery expression column is assumed. For example:
(... COLUMNS xyz)
is equivalent to
XMLTable(... COLUMNS xyz PATH 'XYZ')
You can use different PATH clauses to split the XQuery result into different virtual-table columns.
列 xyz
被假定为 'XYZ'
的原因是因为 Oracle 默认情况下不区分大小写(默认为全部大写)。如果您将列定义为 "aBcD"
,则 PATH
值将假定为 'aBcD'
关于您关于指定数据类型的第二个问题:如果您要提取的数据始终是文本数据,您或许可以不指定数据类型。
但是,如果您开始处理日期、时间戳、浮点数等内容,那么您可能 运行 会遇到问题。您需要使用 TO_*
函数手动转换它们,或者您可以在列定义中指定它们的数据类型。如果您不这样做,Oracle 可以自由地隐式转换它,但它感觉合适,这可能会产生意想不到的后果。