使用变量在Oracle中的XMLTable中定义路径

时间:2016-03-15 13:31:35

标签: xml oracle xpath xmltable

我正在学习如何在Oracle 11g中使用XMLQuery和XMLtable功能,而我在使用XMLTable查询时尝试在XPath中使用变量而不是特定字符串。 例如:

    echo Please enter admin credentials (This will be stored in a secure string:
    powershell -Command "& { read-host -assecurestring | convertfrom- securestring | out-file C:\S3BS\reports\input.txt; } "

我使用此查询来解析XML。但在某些情况下,XML是不同的,我有一个新的XPath。我试图将XPath放在这样的变量中:

DECLARE
   px_return    XMLTYPE
      := XMLTYPE (
            '<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP:Header xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
    </SOAP:Header>
    <SOAP:Body xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
        <n0:validatePolicyCancelResponse xmlns:n0="urn:enterprise.com/ws/SAP/Finantial/MaintainMandate/V1">
            <return>
                <messageType>E</messageType>
            </return>
        </n0:validatePolicyCancelResponse>
    </SOAP:Body>
</soap:Envelope>');

   lv_msgType   VARCHAR2 (20);
   lv_urlString VARCHAR2 (40);
BEGIN
   SELECT Return.msgType
     INTO lv_msgType
     FROM XMLTABLE (
             xmlnamespaces (
                DEFAULT 'enterprise.com/ws/SAP/Finantial/MaintainMandate/V1',
                'http://schemas.xmlsoap.org/soap/envelope/' AS "soap",
                'http://schemas.xmlsoap.org/soap/envelope/' AS "SOAP",
                'enterprise.com/ws/SAP/Finantial/MaintainMandate/V1' AS "n0"),
             '//soap:Envelope/SOAP:Body/n0:validatePolicyCancelResponse/return'
             PASSING px_return
             COLUMNS msgType VARCHAR2 (1) PATH 'messageType') Return;


   DBMS_OUTPUT.put_line ('Message type: ' || lv_msgType);
END;

并在XMLTable查询中替换为:

lv_urlString :=
      '//soap:Envelope/SOAP:Body/n0:validatePolicyCancelResponse/return';

我收到错误:

SELECT Return.msgType
     INTO lv_msgType
     FROM XMLTABLE (
             xmlnamespaces (
                DEFAULT 'enterprise.com/ws/SAP/Finantial/MaintainMandate/V1',
                'http://schemas.xmlsoap.org/soap/envelope/' AS "soap",
                'http://schemas.xmlsoap.org/soap/envelope/' AS "SOAP",
                'enterprise.com/ws/SAP/Finantial/MaintainMandate/V1' AS "n0"),
             lv_urlString
             PASSING px_return
             COLUMNS msgType VARCHAR2 (1) PATH 'messageType') Return;

任何人都可以通过重复使用相同的查询,但应用不同的路径来帮助我这样做吗?

2 个答案:

答案 0 :(得分:2)

我遇到了同样的问题(11.2.0.3.0和12.1.0.2.0)。当查询字符串引用命名空间时,您似乎无法在xmltable处使用PL / SQL变量代替 XQuery_string 。请注意,如果您没有引用命名空间,则可以使用PL / SQL变量(参见下面的示例#3)。

引发的异常description

  

LPX-01081:[XPST0081]前缀无效

     

原因:如果查询中使用的QName包含无法通过使用静态已知名称空间扩展到名称空间URI的名称空间前缀,则会出现静态错误。

     

行动:无

如果使用变量而不是字符串文字的事实似乎被Oracle弃用了。 Oracle支持文档Doc ID 1490150.1(仅适用于付费客户)表明存在补丁(案例与我们的案例不完全相同但非常相似)但文档还指出:

  • 使用变量而不是字符串文字不是SQL / XML标准行为
  • 在运行时构造XPath / XQuery会造成严重的性能损失

因此Oracle建议仅​​使用字符串文字。

我最初的困惑是由Oracle自己的文档(11.2)中的以下冲突引起的:

XMLTABLE SQL/XML Function in Oracle XML DB中的

XML DB Developer's Guide

  

XQuery_string 是一个完整的XQuery表达式,可能包含一个prolog,作为文字字符串

XMLTABLE中的

Database SQL Language Reference

  

XQuery_string 是一个完整的XQuery表达式,可以包含prolog声明。

请注意缺少的&#34;作为字符串文字&#34; 来自第二个引号。当然,我首先只阅读数据库SQL语言参考 ...

XMLTABLE文档已在12.1 version中修复:

  

XQuery_string 是一个文字字符串。它是一个完整的XQuery表达式,可以包含prolog声明。

所以答案是不要将变量用作 XQuery_string ,即使它编译,在某些情况下似乎也能正常工作。

在下面您将找到重现问题的最小示例:

示例#1

这适用于打印&#39;这是A。&#39;如预期的那样。

declare
  v_xml constant xmltype := xmltype('
<ns:a
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:ns="http://stackoverflow.com/users/272735/a">
  <foo><bar>This is A.</bar></foo>
</ns:a>
');
  v_content varchar2(100);
begin
  select bar into v_content
  from xmltable(
    xmlnamespaces('http://stackoverflow.com/users/272735/a' as "ns")
    ,'/ns:a/foo' passing v_xml
    columns
    bar varchar2(4000) path 'bar'
  );

  dbms_output.put_line(v_content);
end;
/

示例#2

这失败了:

ORA-19112: error raised during evaluation:
XVM-01081: [XPST0081] Invalid prefix
1   /ns:a/foo
-   ^

declare
  v_xml constant xmltype := xmltype('
<ns:a
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:ns="http://stackoverflow.com/users/272735/a">
  <foo><bar>This is A.</bar></foo>
</ns:a>
');
  v_xquery_string constant varchar2(100) := '/ns:a/foo';
  v_content varchar2(100);
begin
  select bar into v_content
  from xmltable(
    xmlnamespaces('http://stackoverflow.com/users/272735/a' as "ns")
    ,v_xquery_string passing v_xml
    columns
    bar varchar2(4000) path 'bar'
  );

  dbms_output.put_line(v_content);
end;
/

示例#3

这适用于打印&#39;这是A。&#39;如预期的那样。

declare
  v_xml constant xmltype := xmltype('<a><foo><bar>This is A.</bar></foo></a>');
  v_xquery_string constant varchar2(100) := '/a/foo';
  v_content varchar2(100);
begin
  select bar into v_content
  from xmltable(
    v_xquery_string passing v_xml
    columns
    bar varchar2(4000) path 'bar'
  );

  dbms_output.put_line(v_content);
end;
/

答案 1 :(得分:1)

似乎您在XML中使用了错误的XML名称空间前缀 使用的前缀是soap,但名称空间声明是

xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/

尝试将其更改为肥皂

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/

但这并不能解释所描述的问题