如何在标签的 url 部分提取 Oracle XML

How to extract Oracle XML when url part of tag

我对 XML 的了解还不够,不知道使用什么术语来提问。我将混淆我正在尝试解码的 XML 片段,希望不会混淆到使问题无法回答的地步。

我有一些 XML,我想获取值“要获取的第一个字符串”和“要获取的第二个字符串”。我如何编写 Oracle 查询来获取它们?

<itemTypes>
<itemTypesList>
    <itemType>400SVFD2</itemType>
    <ora:itemType xmlns:ora="http://www.oracle.com/something/somethingelse" navOpt="itemTypeMaint" searchZone="C1-ITEMTYPQ" tblKeyField="ITEM_TYPE_CD">First String to Get</ora:itemType>
    <errorIfNoValue>C1NO</errorIfNoValue>
    <valueType>U</valueType>
    <valueSource>C1BF</valueSource>
    <value/>
    <billFactor>400SVFD2</billFactor>
    <ora:billFactor xmlns:ora="http://www.oracle.com/something/somethingelse" navOpt="billFactorMaint" searchZone="C1-BFQ" tblKeyField="BF_CD">Second String to Get</ora:billFactor>
    <valueAlgorithm/>
</itemTypesList>

如果我编写一个 XML 查询并放入整个标记,如果其中一些字段发生变化会怎样?所以我认为我应该能够仅指示“ora:itemType”和“ora:billFactor”,而基本上忽略其余部分,对吗?

这个returns空:

with test_table(xmldata) as (
select 
q'[
<root>
    <itemTypes>
    <itemTypesList>
        <itemType>400SVFD2</itemType>
        <ora:itemType xmlns:ora="http://www.oracle.com/something/somethingelse" navOpt="itemTypeMaint" searchZone="C1-ITEMTYPQ" tblKeyField="ITEM_TYPE_CD">First String to Get</ora:itemType>
        <errorIfNoValue>C1NO</errorIfNoValue>
        <valueType>U</valueType>
        <valueSource>C1BF</valueSource>
        <value/>
        <billFactor>400SVFD2</billFactor>
        <ora:billFactor xmlns:ora="http://www.oracle.com/something/somethingelse" navOpt="billFactorMaint" searchZone="C1-BFQ" tblKeyField="BF_CD">Second String to Get</ora:billFactor>
        <valueAlgorithm/>
    </itemTypesList>
</itemTypes>
</root>
]'
from dual
)
select
  xmlcast(
     xmlquery(
        '/root/itemTypes/itemTypesList/ora:itemType/text()'
         passing xmltype(xmldata)
         returning content
     )
     as varchar2(100)
   ) res
from test_table
;

URL 是一个命名空间。您可以在 XPath 中声明它。但是 ora 似乎是保留的,因为它仍然为空,因此您可以将其更改为其他内容(仅在查询中,而不是在 XML 文档中):

        'declare namespace xyz="http://www.oracle.com/something/somethingelse";
         /root/itemTypes/itemTypesList/xyz:itemType'

所以在上下文中:

select
  xmlcast(
     xmlquery(
        'declare namespace xyz="http://www.oracle.com/something/somethingelse";
         /root/itemTypes/itemTypesList/xyz:itemType'
         passing xmltype(xmldata)
         returning content
     )
     as varchar2(100)
   ) res
from test_table

db<>fiddle

因为您想要多个值,所以您最好使用 XMLTable:

select x.*
from test_table tt
cross join xmltable(
  xmlnamespaces('http://www.oracle.com/something/somethingelse' as "xyz"),
  '/root/itemTypes/itemTypesList'
  passing xmltype(tt.xmldata)
  columns first_str varchar2(30) path 'xyz:itemType',
    second_str varchar2(30) path 'xyz:billFactor'
) x

db<>fiddle

Read more

第一个变体(使用带 xpath 过滤器的 xmlquery):

with test_table(xmldata) as (
select 
q'[
<root>
    <itemTypes>
    <itemTypesList>
        <itemType>400SVFD2</itemType>
        <ora:itemType xmlns:ora="http://www.oracle.com/something/somethingelse" navOpt="itemTypeMaint" searchZone="C1-ITEMTYPQ" tblKeyField="ITEM_TYPE_CD">First String to Get</ora:itemType>
        <errorIfNoValue>C1NO</errorIfNoValue>
        <valueType>U</valueType>
        <valueSource>C1BF</valueSource>
        <value/>
        <billFactor>400SVFD2</billFactor>
        <ora:billFactor xmlns:ora="http://www.oracle.com/something/somethingelse" navOpt="billFactorMaint" searchZone="C1-BFQ" tblKeyField="BF_CD">Second String to Get</ora:billFactor>
        <valueAlgorithm/>
    </itemTypesList>
</itemTypes>
</root>
]'
from dual
)
select 
  xmlcast(
     xmlquery(
        '/root/itemTypes/itemTypesList/*:itemType[namespace-uri()="http://www.oracle.com/something/somethingelse"]/text()'
         passing xmltype(xmldata)
         returning content
     )
     as varchar2(100)
   ) res1
 ,xmlcast(
     xmlquery(
        '/root/itemTypes/itemTypesList/*:billFactor[namespace-uri()="http://www.oracle.com/something/somethingelse"]/text()'
         passing xmltype(xmldata)
         returning content
     )
     as varchar2(100)
   ) res2
from test_table
/

结果:

RES1                           RES2
------------------------------ ------------------------------
First String to Get            Second String to Get

NB 你的元素在 xmlnamespace 'ora',所以你需要指定它,但是因为 xmlquery 没有 XMLNAMESPACES参数,您有 2 个选择来指定它们:

  1. 在您的 xquery 的开头添加 xmlnamespace 声明:
'declare namespace ora = "http://www.oracle.com/something/somethingelse";...
  1. 或使用函数 namespace-uri():
  2. 过滤元素
*:itemType[namespace-uri()="http://www.oracle.com/something/somethingelse"]

*:element 意味着您需要来自任何 xml 命名空间的 element[namespace-uri()="..."] 按命名空间过滤元素。

第二种变体:usint xmltable(xmlnamespaces(...)...)

with test_table(xmldata) as (
select 
q'[
<root>
    <itemTypes>
    <itemTypesList>
        <itemType>400SVFD2</itemType>
        <ora:itemType xmlns:ora="http://www.oracle.com/something/somethingelse" navOpt="itemTypeMaint" searchZone="C1-ITEMTYPQ" tblKeyField="ITEM_TYPE_CD">First String to Get</ora:itemType>
        <errorIfNoValue>C1NO</errorIfNoValue>
        <valueType>U</valueType>
        <valueSource>C1BF</valueSource>
        <value/>
        <billFactor>400SVFD2</billFactor>
        <ora:billFactor xmlns:ora="http://www.oracle.com/something/somethingelse" navOpt="billFactorMaint" searchZone="C1-BFQ" tblKeyField="BF_CD">Second String to Get</ora:billFactor>
        <valueAlgorithm/>
    </itemTypesList>
</itemTypes>
</root>
]'
from dual
)
select 
  xx.*
from test_table
    ,xmltable(
        xmlnamespaces('http://www.oracle.com/something/somethingelse' as "ORA", default ''),
        '/root/itemTypes/itemTypesList'
         passing xmltype(xmldata)
         columns
             res1   varchar2(100) path 'ORA:itemType/text()'
            ,res2   varchar2(100) path 'ORA:billFactor/text()'
    ) xx
;

结果:

RES1                           RES2
------------------------------ ------------------------------
First String to Get            Second String to Get

1 row selected.

还有一些基于通配符命名空间和过滤器的较短变体:

select
  xmlcast(
     xmlquery(
        '/root/itemTypes/itemTypesList/*:itemType[namespace-uri()!=""]/text()'
         passing xmltype(xmldata)
         returning content
     )
     as varchar2(100)
   ) res1
  ,xmlcast(
     xmlquery(
        '/root/itemTypes/itemTypesList/*:billFactor[2]/text()'
         passing xmltype(xmldata)
         returning content
     )
     as varchar2(100)
   ) res2
from test_table

第一个 returns 具有非空命名空间 uri 的元素,第二个 returns 第二个 billFactor 没有按命名空间过滤