Как извлечь Oracle XML из URL-адреса тега - PullRequest
2 голосов
/ 14 июля 2020

Я не знаю 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» и по существу игнорировать остальные, верно?

Это возвращает 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
;

Ответы [ 2 ]

2 голосов
/ 14 июля 2020

Первый вариант (с использованием xmlquery с фильтром xpath) :

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. добавить объявление xmlnamespace в начале вашего xquery:
'declare namespace ora = "http://www.oracle.com/something/somethingelse";...
или фильтрующие элементы с использованием функции namespace-uri():
*:itemType[namespace-uri()="http://www.oracle.com/something/somethingelse"]

*:element означает, что вам нужно element из любых пространств имен xml. [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

Первый возвращает элемент с непустым пространством имен-uri, а второй - просто возвращает второй billFactor без фильтрации по пространствам имен

0 голосов
/ 14 июля 2020

URL-адрес - это пространство имен. Вы можете объявить это в своем XPath. Но ora кажется зарезервированным, так как он по-прежнему получает значение null, поэтому вы можете изменить его на что-то еще (только в запросе, а не в документе XML):

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

так что в context:

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

Подробнее

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...