2015-02-25 8 views
2

У меня этот XML.Чтение элементов XML-элементов с использованием PL SQL

<a> 
    <b>b1</b> 
    <c>c1</c> 
    <b>b2</b> 
    <c>c2</c2> 
</a> 

Я хочу, чтобы иметь возможность извлекать значения элементов «b» и «c» с помощью PL \ SQL. Я использую Oracle 10g.

До сих пор у меня есть это,

SELECT XML.b      
     , XML.c 
    FROM XMLTable (
      '/a' PASSING p_xml 
       COLUMNS 
       b   VARCHAR(2) PATH 'b/.' 
       , c   VARCHAR(2) PATH 'c/.' 
    ) XML 

Но я получаю эту ошибку:

19279. 00000 - "XQuery dynamic type mismatch: expected singleton sequence - got multi-item sequence" 
*Cause: The XQuery sequence passed in had more than one item. 
*Action: Correct the XQuery expression to return a single item sequence. 

Затем я попытался это:

SELECT XML.b      
     , XML1.c 
    FROM XMLTable (
      '/a/b' PASSING p_xml 
       COLUMNS 
       b   VARCHAR(2) PATH '.' 
    ) XML, 
     XMLTable (
      '/a/c' PASSING p_xml 
       COLUMNS 
       c   VARCHAR(2) PATH '.' 
    ) XML1 

Но результаты были:

b1,c1 
b1,c2 
b2,c1 
b2,c2 

Когда я хочу только: b1 c1 b2 c2

Можете ли вы, ребята, мне помочь?

ответ

1

Я не запускал его, но насколько я вижу ниже код должен работать;

DECLARE 
vs_Xml VARCHAR2(32000):= '<INPUT> 
    <A> 
    <B>1</B> 
    </A> 
    <A> 
    <B>2</B> 
    </A> 
</INPUT>'; 

vx_ParameterList XMLTYPE; 
vx_Parameter  XMLTYPE; 
vn_ParameterIndex NUMBER; 
vs_Key    VARCHAR2(64); 
vs_XPath   VARCHAR2(255); 
vs_Value   VARCHAR2(10000); 

BEGIN 
vx_ParameterList := xmltype(vs_Xml); 
vn_ParameterIndex := 1; 
vs_XPath := '/INPUT/A'; 

WHILE vx_ParameterList.existsNode(vs_XPath || '[' || vn_ParameterIndex || ']') = 1 LOOP 
    vx_Parameter := vx_ParameterList.extract(vs_XPath || '[' || vn_ParameterIndex || ']'); 

    vs_Value := vx_Parameter.extract('//B/text()').GetStringVal(); 
    vn_ParameterIndex := vn_ParameterIndex + 1; 

    dbms_output.put_line(vs_Value); 
END 
1

Вы должны настроить выражение XQuery в команде XMLTABLE. Основная идея - создать поток записей xml, каждый из которых может быть сопоставлен столбцам записи базы данных.

Препятствие в исходном xml заключается в том, что ось xpath /a возвращается - фраза sloppily - содержимое все xml records.

Решение состоит в том, чтобы построить итератор над /a, который поставляет записи xml один за другим (технически: завернутый в синтетический элемент x).

Следующая может быть выдан из SQLPLUS:

 SELECT myxml.b 
      , myxml.c        
     FROM XMLTable (
'for $i in (1, let $x := fn:count(/a/b) return $x) 
let $b := /a/b[$i], $c := /a/c[$i] 
return <x> 
      <b>{$b}</b> 
      <c>{$c}</c> 
     </x> 
' PASSING XMLTYPE(
'<a> 
    <b>b1</b> 
    <c>c1</c> 
    <b>b2</b> 
    <c>c2</c> 
</a>') 
        COLUMNS 
        b   VARCHAR(2) PATH '/x/b' 
        , c   VARCHAR(2) PATH '/x/c' 
     ) myxml 
; 

Update

Для того, чтобы обеспечить произвольное число b/c детей, в следующей строке

for $i in (1, let $x := fn:count(/a/b) return $x) 

Заменяет оригинал

for $i in (1, 2) 

в вышеуказанном выражении.

Ссылка

Более подробная информация о синтаксисе XQuery можно найти в W3c spec (глубоководных ссылки на синтаксической док Forthe так называемых FWLOR выражения).

Смежные вопросы