【问题标题】:Trying to loop through XML to extract values in PLSQL尝试循环通过 XML 提取 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;

【问题讨论】:

    标签: xml plsql


    【解决方案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 上运行。我希望您尝试一个查询,它相当于我添加到我的问题中的存储过程 - 当您运行它时,您仍然会收到错误吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      相关资源
      最近更新 更多