我有这个XML。
<a>
<b>b1</b>
<c>c1</c>
<b>b2</b>
<c>c2</c2>
</a>
我希望能够使用PL\SQL提取元素'b'和'c'的值。我使用的是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
当我只想要:b1c1b2c2
你们能帮我吗?
我没有运行它,但据我所见,下面的代码应该可以工作;
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
您必须调整XMLTABLE
命令中的xquery表达式。其基本思想是生成一个xml记录流,每个记录都可以映射到数据库记录的列。
原始xml中的障碍是xpath轴/a
返回所有xml记录的内容(措辞草率)。
解决方案是在/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
;
更新
为了允许任意数量的b
/c
子级,以下行
for $i in (1, let $x := fn:count(/a/b) return $x )
取代原来的
for $i in (1, 2)
在上面的表达式中。
参考
有关XQuery语法的更多信息可以在W3c规范中找到(所谓FWLOR表达式的语法文档的深层链接)。