尝试循环通过 XML 提取 PLSQL 中的值

Posted

技术标签:

【中文标题】尝试循环通过 XML 提取 PLSQL 中的值【英文标题】:Trying to loop through XML to extract values in PLSQL 【发布时间】:2016-11-15 16:27:15 【问题描述】:

我正在尝试遍历 XML 并提取 UUID。我有以下内容,它循环正确的次数并每次打印一个空白行。为什么不提取 UUID 节点的文本值?

   DECLARE
       X XMLTYPE := XMLTYPE('<?xml version="1.0" ?> 
         <StatusUp>
           <G_UUIDs>
               <UUID>1 test 1</UUID>
               <UUID>2 test 2</UUID>
               <UUID>3 test 3 </UUID>
               <UUID>4 test 4 </UUID>
           </G_UUIDs>
        </StatusUp>');
    BEGIN
       FOR r IN (SELECT EXTRACTVALUE(VALUE(p), 'StatusUp/G_UUIDs/UUID/text()') AS uuid

                   FROM TABLE(XMLSEQUENCE(EXTRACT(X, '//StatusUp/G_UUIDs/UUID'))) p)
       LOOP
          DBMS_OUTPUT.PUT_LINE('UUID' || r.uuid);
       END LOOP;
    END;

【问题讨论】:

【参考方案1】:

您已经在 FROM 语句中从 XML 中提取了 UUID,而在 select 中,形象地说,您现在只有四行

<UUID> n test n </UUID>

所以提取数据的正确方法是:

DECLARE
  X XMLTYPE := XMLTYPE(
    '<?xml version="1.0" ?> 
    <StatusUp>
      <G_UUIDs>
        <UUID>1 test 1</UUID>
        <UUID>2 test 2</UUID>
        <UUID>3 test 3 </UUID>
        <UUID>4 test 4 </UUID>
      </G_UUIDs>
    </StatusUp>');
BEGIN
  FOR r IN (SELECT
              EXTRACTVALUE(
                VALUE(p),
                --'StatusUp/G_UUIDs/UUID/text()') AS uuid
                '/UUID/text()') AS uuid
            FROM
              TABLE(
                XMLSEQUENCE(
                  EXTRACT(
                    X,
                    '//StatusUp/G_UUIDs/UUID')
                )
              ) p
           )
  LOOP
    DBMS_OUTPUT.PUT_LINE(r.uuid);
  END LOOP;
END;

【讨论】:

【参考方案2】:

如果您要将其转换为 sql 语句并运行它,如下所示:

WITH sample_data AS (SELECT XMLTYPE('<?xml version="1.0" ?> 
         <StatusUp>
           <G_UUIDs>
               <UUID>1 test 1</UUID>
               <UUID>2 test 2</UUID>
               <UUID>3 test 3 </UUID>
               <UUID>4 test 4 </UUID>
           </G_UUIDs>
        </StatusUp>') x FROM dual)
SELECT p.*,
       EXTRACTVALUE(VALUE(p), 'StatusUp/G_UUIDs/UUID/text()') AS uuid
FROM   sample_data sd,
       TABLE(XMLSEQUENCE(EXTRACT(sd.x, '//StatusUp/G_UUIDs/UUID'))) p;

很容易发现问题:

COLUMN_VALUE             UUID
------------------------ ----------
<UUID>1 test 1</UUID>
<UUID>2 test 2</UUID>
<UUID>3 test 3 </UUID> 
<UUID>4 test 4 </UUID>

即您正在尝试从仅包含节点 UUID 的 xml 中提取节点 StatusUp/G_UUIDs/UUID。相反,如果您更正要查询的节点,您会得到正确的结果:

DECLARE
   X XMLTYPE := XMLTYPE('<?xml version="1.0" ?> 
     <StatusUp>
       <G_UUIDs>
           <UUID>1 test 1</UUID>
           <UUID>2 test 2</UUID>
           <UUID>3 test 3 </UUID>
           <UUID>4 test 4 </UUID>
       </G_UUIDs>
    </StatusUp>');
BEGIN
   FOR r IN (SELECT EXTRACTVALUE(VALUE(p), 'UUID/text()') AS uuid
               FROM TABLE(XMLSEQUENCE(EXTRACT(X, '//StatusUp/G_UUIDs/UUID'))) p)
   LOOP
      DBMS_OUTPUT.PUT_LINE('UUID' || r.uuid);
   END LOOP;
END;
/

UUID1 test 1
UUID2 test 2
UUID3 test 3 
UUID4 test 4 

但是,不推荐使用 EXTRACT 和 EXTRACTVALUE - 您应该改用 XMLTABLE:

DECLARE
   X XMLTYPE := XMLTYPE('<?xml version="1.0" ?> 
     <StatusUp>
       <G_UUIDs>
           <UUID>1 test 1</UUID>
           <UUID>2 test 2</UUID>
           <UUID>3 test 3 </UUID>
           <UUID>4 test 4 </UUID>
       </G_UUIDs>
    </StatusUp>');
BEGIN
   FOR r IN (SELECT *
             FROM   XMLTABLE('//StatusUp/G_UUIDs/UUID'
                             PASSING x
                             COLUMNS uuid varchar2(10) PATH '.'))
   LOOP
      DBMS_OUTPUT.PUT_LINE('UUID' || r.uuid);
   END LOOP;
END;
/

UUID1 test 1
UUID2 test 2
UUID3 test 3 
UUID4 test 4 

您应该尝试运行的等效查询:

WITH sample_data AS (SELECT XMLTYPE('<?xml version="1.0" ?> 
         <StatusUp>
           <G_UUIDs>
               <UUID>1 test 1</UUID>
               <UUID>2 test 2</UUID>
               <UUID>3 test 3 </UUID>
               <UUID>4 test 4 </UUID>
           </G_UUIDs>
        </StatusUp>') x FROM dual)
SELECT *
FROM   sample_data sd,
       XMLTABLE('//StatusUp/G_UUIDs/UUID'
                PASSING sd.x
                COLUMNS uuid varchar2(10) PATH '.');

【讨论】:

谢谢,我刚刚发现了 extractvalue 节点错误的问题,正准备回答我自己的问题。我不知道 XMLTABLE 并将查看它。 我在运行 xmltable 建议时遇到错误,具体来说:第 1 行错误 ORA-19114:解析 XQuery 表达式时出错:java.lang.NoClassDefFoundError ORA-06512:第 12 行跨度> 您是否收到我给您的代码的错误?因为这对我来说没有错误。如果是这样,您在哪个版本的 Oracle 上运行它? @bonesit 我在 Oracle 10g 上,是的,我试图运行的正是你的代码。 嗯。它绝对可以在 11.2.0.4 上运行。我希望您尝试一个查询,它相当于我添加到我的问题中的存储过程 - 当您运行它时,您仍然会收到错误吗?

以上是关于尝试循环通过 XML 提取 PLSQL 中的值的主要内容,如果未能解决你的问题,请参考以下文章

循环在尝试通过 Oracle EBS 中的并发程序使用 PL/SQL 创建 XML 时提前结束

基于子元素值使用 PLSQL 提取 XML

如何选择与 PLSQL 中的值匹配的子 XML?

PLSQL中的批量插入而不是循环?

PLSQL 中的 WHILE 循环有啥问题?

循环遍历多个表的 plsql 代码