如何在 Oracle 中使用命名空间查询 XML?

Chr*_* P. 5 xml xpath xquery plsql namespaces

我需要从包含完整 XML 文档的 XMLType 变量中提取 PLSQL 过程中的数据,其结构如下(简化后):

<?xml version="1.0" encoding="utf-8"?>
<AA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://my.domain/cat1/">
  <Element>
    <ID>2</ID>
    <Value>46544</Value>
  <Element>
</AA>
Run Code Online (Sandbox Code Playgroud)

我正在使用 XMLTable 函数,但使用简单的/AA/ElementXPath 表达式无法获取数据:

SELECT C1, C2
INTO v_id, v_val
FROM XMLTable('/AA/Element'
                   passing v_MyXML columns
                    C1 number path 'ID',
                    C2 number path 'Value'
                )
Run Code Online (Sandbox Code Playgroud)

也不与以下任何表达式一起使用:

'/*.AA/Element'
'declare default element namespace "http://my.domain/cat1/"; /AA/Element'
'declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance"; declare namespace xsd="http://www.w3.org/2001/XMLSchema"; declare default element namespace "http://jpk.mf.gov.pl/wzor/2016/03/09/03094/"; /AA/Element'
Run Code Online (Sandbox Code Playgroud)

我能够提取数据的唯一方法是修改文档/变量并简单地替换

<AA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://my.domain/cat1/">
Run Code Online (Sandbox Code Playgroud)

<AA>
Run Code Online (Sandbox Code Playgroud)

这不是完美的解决方案,因为我需要修改文档并返回具有适当属性的初始结构。有人可以建议如何修改 XPath 表达式以便能够获取数据吗?或者也许使用任何其他方法忽略 AA 元素中的名称空间?

use*_*735 2

@JensErat 已经提供了 XML 背景,所以我不必这样做。相反,您将在下面找到一个如何在 Oracle PL/SQL 中应用所有这些内容的工作示例。

您需要使用xmltableXML 命名空间子句

XMLNAMESPACES 子句包含一组 XML 命名空间声明。这些声明由 XQuery 表达式(计算的 XQuery_string)和 XML_table_column 的 PATH 子句中的 XPath 表达式引用,前者计算行,后者计算整个 XMLTable 函数的列。如果要在 COLUMNS 子句的 PATH 表达式中使用限定名称,则需要指定 XMLNAMESPACES 子句。

您还可以使用默认的XML 命名空间子句:

xmlnamespaces(default 'http://my.domain/cat1/')
Run Code Online (Sandbox Code Playgroud)

那么您不必使用名称空间前缀。

没有默认命名空间的示例

declare
  v_xml constant xmltype := xmltype('<AA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://my.domain/cat1/">
  <Element>
    <ID>2</ID>
    <Value>46544</Value>
  </Element>
</AA>'
);
 v_id number;
 v_value number;
begin
  select   id,   value_
    into v_id, v_value
  from xmltable(
    xmlnamespaces('http://my.domain/cat1/' as "foo"),
    '/foo:AA/foo:Element' passing v_xml
    columns
    id number path 'foo:ID',
    value_ number path 'foo:Value'
  );

  dbms_output.put_line('(v_id = ' || v_id || ')(v_value = ' || v_value || ')');
end;
/
Run Code Online (Sandbox Code Playgroud)

使用默认命名空间的示例

declare
  v_xml constant xmltype := xmltype('<AA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://my.domain/cat1/">
  <Element>
    <ID>2</ID>
    <Value>46544</Value>
  </Element>
</AA>'
);
 v_id number;
 v_value number;
begin
  select   id,   value_
    into v_id, v_value
  from xmltable(
    xmlnamespaces(default 'http://my.domain/cat1/'),
    '/AA/Element' passing v_xml
    columns
    id number path 'ID',
    value_ number path 'Value'
  );

  dbms_output.put_line('(v_id = ' || v_id || ')(v_value = ' || v_value || ')');
end;
/
Run Code Online (Sandbox Code Playgroud)

运行示例:

SQL> @so58
(v_id = 2)(v_value = 46544)

PL/SQL procedure successfully completed.

SQL>
Run Code Online (Sandbox Code Playgroud)