【问题标题】:Using variable to define path in XMLTable in Oracle在 Oracle 中使用变量在 XMLTable 中定义路径
【发布时间】:2016-06-30 23:32:51
【问题描述】:

我正在学习如何在 Oracle 11g 中使用 XMLQuery 和 XMLtable 功能,并且在使用 XMLTable 查询时,我尝试在 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;

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

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

并在 XMLTable 查询中替换为:

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;

我得到错误:

ORA-19112: error raised during evaluation: 
XVM-01081: [XPST0081] Invalid prefix

谁能通过重复使用相同的查询但应用不同的路径来帮助我做到这一点?

【问题讨论】:

  • 也许RETURN被认为是保留字,试试别的,例如ret
  • 对不起,但是在查询中作为字符串在路径中使用时返回它是可以的

标签: xml oracle xpath xmltable


【解决方案1】:

我遇到了同样的问题(在 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 in XML DB Developer's Guide:

XQuery_string 是一个完整的 XQuery 表达式,可能包括一个序言,作为文字字符串。

XMLTABLE in Database SQL Language Reference:

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

注意第二个引号中缺少的 "as a string literal"。当然,我首先只阅读数据库 SQL 语言参考 ...

XMLTABLE 文档已在12.1 version 中修复:

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

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

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

示例 #1

这有效并打印出“这是 A。”正如预期的那样。

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

这有效并打印出“这是 A。”正如预期的那样。

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;
/

【讨论】:

    【解决方案2】:

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

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

    尝试将其更改为肥皂

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

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

    【讨论】:

      猜你喜欢
      • 2013-05-15
      • 1970-01-01
      • 1970-01-01
      • 2016-03-04
      • 2022-01-02
      • 2020-05-04
      • 2014-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多