使用 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;

我对命名空间使用通配符,因为我真的不在乎发送方对命名空间使用什么缩写,无论如何我都知道获取数据的确切路径。

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

编辑:

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

一起工作

可运行代码示例:

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 可以自由地隐式转换它,但它感觉合适,这可能会产生意想不到的后果。