使用 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,'&lt;','<');
        l_html_build := replace(l_html_build,'&gt;','>');
        l_html_build := replace(l_html_build,'&amp;lt;','');
        l_html_build := replace(l_html_build,'&amp;gt;','');
        l_html_build := replace(l_html_build,'&amp;nbsp;','&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,'&amp;lt;','&lt;');
   l_html_build := replace(l_html_build,'&amp;gt;','&gt;');
   l_html_build := replace(l_html_build,'&amp;nbsp;','&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,'&lt;description', '&lt;div class="description"'); 更改为 regexp_replace(l_html_build,'&lt;(description|status|whatever)', '&lt;div class="\1"');replace(l_html_build,'&lt;/description&gt;', '&lt;/div&gt;'); 更改为 replace(l_html_build,'&lt;/(description|status|whatever)&gt;', '&lt;/div&gt;'); 关于 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,'&lt;','<');
        l_html_build := replace(l_html_build,'&gt;','>');
        l_html_build := replace(l_html_build,'&amp;lt;','');
        l_html_build := replace(l_html_build,'&amp;gt;','');
        l_html_build := replace(l_html_build,'&amp;nbsp;','&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 中的嵌套对象

我正在尝试在 PL/SQL 中解析 XML。我无法从标签中检索属性值,我做错了啥?

如何在 PL/SQL 中解析 XML

如何使用 PL SQL 输出这种 XML 格式