当标签的url部分时如何提取Oracle XML
Posted
技术标签:
【中文标题】当标签的url部分时如何提取Oracle XML【英文标题】:How to extract Oracle XML when url part of tag 【发布时间】:2020-11-03 04:25:56 【问题描述】:我对 XML 的了解不够深入,无法知道使用什么术语来提出问题。我将混淆我试图解码的 XML sn-p,希望不会使问题无法回答。
我有一些 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”,而基本上忽略其余的,对吧?
这将返回 null:
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
;
【问题讨论】:
【参考方案1】:第一个变体(使用带有 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 个选择来指定它们:
-
在 xquery 的开头添加 xmlnamespace 声明:
'declare namespace ora = "http://www.oracle.com/something/somethingelse";...
-
或使用函数
namespace-uri()
过滤元素:
*: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
第一个返回具有非空 namespace-uri 的元素,第二个仅返回第二个 billFactor 而不按命名空间过滤
【讨论】:
最后一个例子有现在为我工作的代码。在途中学习很多东西。【参考方案2】: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
【讨论】:
以上是关于当标签的url部分时如何提取Oracle XML的主要内容,如果未能解决你的问题,请参考以下文章