【问题标题】:How to query XML with namespaces in Oracle?如何在 Oracle 中使用命名空间查询 XML?
【发布时间】:2016-11-21 05:32:22
【问题描述】:

我需要从包含完整 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>

我正在使用 XMLTable 函数,但使用简单的 /AA/Element XPath 表达式没有数据:

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

以下任何一个都不是:

'/*.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'

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

<AA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://my.domain/cat1/">

<AA>

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

【问题讨论】:

  • 一个快速而肮脏的解决方案是将您的 XPath 表达式更改为 /*/*[local-name() = 'Element']。最好弄清楚如何正确引用命名空间。

标签: xml xpath plsql namespaces xquery


【解决方案1】:

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

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

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

您也可以使用 default XML 命名空间子句:

xmlnamespaces(default 'http://my.domain/cat1/')

那么你不必使用命名空间前缀。

没有默认命名空间的示例

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

默认命名空间示例

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

示例运行:

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

PL/SQL procedure successfully completed.

SQL>

【讨论】:

    【解决方案2】:
    /*.AA/Element
    

    您需要用冒号 : 分隔命名空间和元素名称,而不是点 .。此外,在这种情况下,命名空间被继承给 &lt;Element/&gt; 孩子,所以正确的查询应该是

    /*:AA/*:Element
    

    您声明默认元素命名空间的查询应该可以正常工作。我找不到 Oracle 不支持这一点的痕迹。

    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
    

    我猜my.domain 命名空间实际上就是这个。最后,这与示例 2 中的查询相同:其他两个命名空间前缀是较新使用的。如果通配符命名空间还是不行,尝试用前缀注册命名空间(选择合适的前缀,可以自己定义):

    declare namespace cat1="http://my.domain/cat1/";
    /cat1:AA/cat1:Element
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 2015-02-06
      • 2011-12-24
      • 2014-04-08
      相关资源
      最近更新 更多