使用XMLTABLE和xquery从xml

时间:2015-05-29 11:42:57

标签: oracle plsql xquery xmltable

我有以下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;

我使用通配符作为命名空间,因为我并不十分关心发送方正在使用命名空间的缩写,我知道无论如何都要获取数据的确切路径。

使用这段代码,我有两件事让我感到困惑:

编辑:

我发现当我删除元素的命名空间并将它们设为大写时,它就可以了。因此,列名称似乎需要匹配xml元素名称才能使其工作。我还没弄明白如何使用命名空间XML。

  • 文档还指出&#34;对于除FOR ORDINALITY列之外的每个结果列,您必须指定列数据类型&#34;但是,没有它它似乎工作正常。为列和为数据提取的变量指定它似乎也有点多余。如果不指定数据类型,任何想法都会让我遇到麻烦吗?

可运行代码示例:

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;                            

2 个答案:

答案 0 :(得分:1)

参考文献:

https://stackoverflow.com/a/9976068/377141

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')

从您的示例中(您可能还需要提前注册您的架构/命名空间,但这应该是一次):

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;

过去在以前版本的Oracle中工作的东西在11g +中不能用于XML,从我所看到的,Oracle强烈验证/输入XML操作的输入/输出,在以前的版本中你可以正常运行没有命名空间信息的正确XQuery操作。

答案 1 :(得分:1)

根据您的第一个问题,the documentation you linked今天就省略了PATH

  

可选的PATH子句指定由XQuery表达式字符串寻址的XQuery结果部分将用作列内容。

     

如果省略PATH,则假定使用XQuery表达式列。例如:

     

(... COLUMNS xyz)

     

相当于

     

XMLTable(... COLUMNS xyz PATH 'XYZ')

     

您可以使用不同的PATH子句将XQuery结果拆分为不同的虚拟表列。

假定列xyz'XYZ'的原因是默认情况下Oracle不区分大小写(默认为全部大写)。如果您已将列定义为"aBcD",那么PATH值将被假定为'aBcD'

关于指定数据类型的第二个问题:如果要提取的数据始终是文本数据,则可能无法指定数据类型。

但是,如果您开始处理日期,时间戳,浮点数等事情,那么您可能会遇到问题。您需要使用TO_*函数手动转换它们,或者您可以在列定义中指定它们的数据类型。如果你不这样做,甲骨文可以自由地暗示它,但它感觉合适,这可能会产生意想不到的后果。