使用 PL SQL 读取 XML 个元素出现
Reading XML element occurrences using PL SQL
我有这个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
当我只想要:
b1
c1
b2
c2
你们能帮帮我吗?
我没有 运行 但据我所知,下面的代码应该可以工作;
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
returns -措辞草率 - all的内容xml条记录。
解决方案是在 /a
上构建一个迭代器,它提供 xml 条记录 one-by-one(技术上:包裹在一个合成的 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
children,下面一行
for $i in (1, let $x := fn:count(/a/b) return $x )
替换原来的
for $i in (1, 2)
在上面的表达式中。
参考
有关 XQuery 语法的更多信息可以在 W3c spec 中找到(deep-links 到 so-called FWLOR 表达式的语法文档)。
我有这个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
当我只想要: b1 c1 b2 c2
你们能帮帮我吗?
我没有 运行 但据我所知,下面的代码应该可以工作;
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
returns -措辞草率 - all的内容xml条记录。
解决方案是在 /a
上构建一个迭代器,它提供 xml 条记录 one-by-one(技术上:包裹在一个合成的 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
children,下面一行
for $i in (1, let $x := fn:count(/a/b) return $x )
替换原来的
for $i in (1, 2)
在上面的表达式中。
参考
有关 XQuery 语法的更多信息可以在 W3c spec 中找到(deep-links 到 so-called FWLOR 表达式的语法文档)。