使用 PL/SQL 解析 XML 输出 html 中特定标签的内容
Posted
技术标签:
【中文标题】使用 PL/SQL 解析 XML 输出 html 中特定标签的内容【英文标题】:Parsing XML outputting the content of specific tags in html using PL/SQL 【发布时间】:2013-02-08 13:29:13 【问题描述】:我目前在使用 PL/SQL 解析某些 XML 时遇到问题。本质上,我有一些 XML 存储在现有函数提供的 clob 变量中。我创建了一个新的 xmltype 变量,用于将 clob 转换为 xmltype。然后我循环遍历这个新的 xmltype 变量的内容,试图提取每个标签的内容并将其输出到自己的 div 中。然而,我的代码目前只是将所有标签的内容输出到一个 div 中,这给人的印象是它根本没有循环。
XML 结构是(显然嵌套了更多的内部标签作为回报):
<?xml version="1.0" encoding="UTF-8"?>
<results>
<return>
<createDate> Date 1 Here </createDate>
<description> Description 1 here </description>
</return>
<return>
<createDate> Date 2 Here </createDate>
<description> Description 2 here </description>
</return>
</results>
我用来循环的PLSQL可以在这里找到:
-- parsing : Parse the xml and wrap description content in a html div
l_html_build := '<!DOCTYPE html><html><head></head><body>';
l_parse_xml := (xmltype(l_xml_response));
l_parse_xml_index := 1;
while l_parse_xml.existsNode('//description[' || To_Char(l_parse_xml_index) || ']') > 0
loop
l_html_build := l_html_build || '<div class="description">';
l_html_build := l_html_build || (xmltype(l_xml_response).extract('//description[' || To_Char(l_parse_xml_index)
|| ']/text()').getclobval());
l_html_build := l_html_build || '</div>';
l_html_build := replace(l_html_build,'<','<');
l_html_build := replace(l_html_build,'>','>');
l_html_build := replace(l_html_build,'&lt;','');
l_html_build := replace(l_html_build,'&gt;','');
l_html_build := replace(l_html_build,'&nbsp;',' ');
l_html_build := l_html_build ||'</body></html>';
l_parse_xml_index := l_parse_xml_index + 1;
end loop;
一些参数和变量的解释可以在下面找到:
l_xml_response clob; -- XML from another function is stored here
l_html_build clob; -- Used as a variable to store the output to be sent to the page
l_parse_xml xmltype; -- l_xml_response content is passed into this xmltype variable which is used for parsing
l_parse_xml_index number; -- Used as an index to assist with looping through the tags
输出如下:
<div class = "description">
Description 1 here Description 2 here
</div>
什么时候应该:
<div class = "description">
Description 1 here
</div>
<div class = "description">
Description 2 here
</div>
任何帮助都将不胜感激,因为我是一名 html/css/php/javascript 程序员,而且我之前没有真正做过 PL/SQL(而且我的老板并没有真正提供任何真正的培训帮助)。
提前致谢!
【问题讨论】:
我将使用 XPath 创建一个 SQL 查询,它返回相关节点的值。 这只能用 PLSQL 代码而不是 SQL 来完成(因为我还没有被告知我可以使用哪些表) 类似这样的东西:sqlfiddle.com/#!4/68b32/66(但我不知道这是否可以在 PL/SQL 中使用 CLOB 变量) XML 已经从 Web 服务生成,因此我们无法根据需要设置它(就像您在此处所做的那样)。目前,所有的 XML 都存储在一个 clob 中。必须对我上面的代码进行修改/调整才能解决这种情况。这就是我的灵感来源:anononxml.blogspot.co.uk/2010/05/… 这只是一个示例,您可以改用 xml 变量。像这样:sqlfiddle.com/#!4/d41d8/7078(请注意,SQFiddle 无法显示来自dbms_output
的输出,但您可以在本地运行)
【参考方案1】:
这似乎比 jme1988 的解决方案效率高出大约一个数量级 - 至少在具有 ~1000 return
记录的玩具示例上。显然我不能说这种方法将如何扩展到您将使用的数据量(但是,它应该可以很好地扩展)。
DECLARE
l_c CLOB;
BEGIN
l_html_build := '<!DOCTYPE html><html><head></head><body>';
l_parse_xml := xmltype(l_xml_response);
--
BEGIN
WITH xdata AS
(
SELECT xmltype ( l_xml_response ) xml
from dual
)
SELECT XMLSERIALIZE ( CONTENT extract(xml, '//description') ) x
INTO l_c
FROM xdata
;
END;
l_html_build := l_html_build || l_c;
--
l_html_build := replace(l_html_build,'<description', '<div class="description"');
l_html_build := replace(l_html_build,'</description>', '</div>');
l_html_build := replace(l_html_build,'&lt;','<');
l_html_build := replace(l_html_build,'&gt;','>');
l_html_build := replace(l_html_build,'&nbsp;',' ');
l_html_build := l_html_build ||'</body></html>';
END;
希望这些东西能满足您的需求。问候,卡斯滕
【讨论】:
这将如何适应检索多个标签?例如,如果 XML 中还有我希望接收的状态标记? 有 2 段代码需要修改。首先将 xmlserialize 函数中的 xpath 表达式从//description
更改为 (//description|//status|//whatever)``. second, you'd change the first uses of
replace` 从 replace(l_html_build,'<description', '<div class="description"');
更改为 regexp_replace(l_html_build,'<(description|status|whatever)', '<div class="\1"');
和 replace(l_html_build,'</description>', '</div>');
更改为 replace(l_html_build,'</(description|status|whatever)>', '</div>');
。
关于 xpath 模式,//*[(local-name()='description' or local-name()='status' or local-name()='whatever')
可能更有效。如果您知道 xml 数据的精确结构,则应将其纳入 xpath 表达式以显着加快处理速度。根据您的示例,例如(/results/return/description|/results/return/status|/results/return/whatever)
。
那么您的基准测试是否仅在 xmlserialize 函数上进行?我已经对这个解决方案和我上面的解决方案进行了一些测试,我的速度略快。
不,我对完整代码进行了基准测试。当然,我的测试远非详尽无遗 - 无论如何,性能取决于数据量、dbms 设置、机器负载、硬件,因此结果只能暗示潜在的性能提升。【参考方案2】:
A_horse_with_no_name 的建议是正确的,但更有效的方法是:
begin
for value_set_rec in
(select extract(value(x),'/description/text()').getclobval() l_description
from table(xmlsequence(xmltype(l_xml_response).extract('//description')))x)
loop
l_html_build := l_html_build || '<div class="description">';
l_html_build := l_html_build || value_set_rec.l_description;
l_html_build := l_html_build || '</div>';
end loop;
exception
when others then
--Error handling here
end;
l_html_build := replace(l_html_build,'<','<');
l_html_build := replace(l_html_build,'>','>');
l_html_build := replace(l_html_build,'&lt;','');
l_html_build := replace(l_html_build,'&gt;','');
l_html_build := replace(l_html_build,'&nbsp;',' ');
l_html_build := l_html_build ||'</body></html>';
【讨论】:
以上是关于使用 PL/SQL 解析 XML 输出 html 中特定标签的内容的主要内容,如果未能解决你的问题,请参考以下文章
使用 pl/sql dom 解析器解析 XML 的最简单方法
使用 SQL 或 PL/SQL 解析 XML 文档以提取字段值
Oracle PL/SQL 使用 XMLTABLE 解析 xml 中的嵌套对象