【问题标题】:Extracting value from xml clob with Namespace using Oracle pl/sql使用 Oracle pl/sql 从带有命名空间的 xml clob 中提取值
【发布时间】:2017-06-13 21:33:51
【问题描述】:

我目前正在尝试从clob 列中提取值,但总是得到null 的结果。

我尝试了许多可能的情况,但对我来说它总是以 null 的形式返回。

附上实际的xml

<TenderOffer xmlns="http://xmlns.oracle.com/apps/otm">
    <Shipment>
        <ShipmentHeader/>
        <SEquipment/>
        <ShipmentStop/>
        <ShipmentStop/>
        <Location/>
        <Location/>
        <Release/>
        <RATE_OFFERING>
            <RATE_OFFERING_ROW>
                <USER_CLASSIFICATION3>ZXF</USER_CLASSIFICATION3>
            </RATE_OFFERING_ROW>
        </RATE_OFFERING>
    </Shipment>
    </TenderOffer>

下面是实际的查询,

select 
        itc.element_name,
        extractvalue(XMLTYPE(XML_BLOB), '/TenderOffer/Shipment/RATE_OFFERING/RATE_OFFERING_ROW/USER_CLASSIFICATION3/text()'),
    XMLTYPE(XML_BLOB)
        from i_transaction itc
        where itc.i_transaction_no = 31553115
            and rownum = 1

【问题讨论】:

  • 验证您的代码是否存在拼写错误,我收到abxy 与您的查询:SELECT EXTRACTVALUE(XMLTYPE('&lt;Header&gt; &lt;SecondHeader&gt; &lt;ThirdHeader&gt; &lt;FourthHeader&gt; &lt;Value1&gt;abcd&lt;/Value1&gt; &lt;Value2&gt;xyz&lt;/Value2&gt; &lt;Value3&gt;abxy&lt;/Value3&gt; &lt;/FourthHeader&gt; &lt;/ThirdHeader&gt; &lt;/SecondHeader&gt; &lt;/Header&gt;'), '/Header/SecondHeader/ThirdHeader/FourthHeader/Value3/text()') FROM dual;
  • 嗨,伙计,我更新了 xml 和实际查询,你能看看吗。谢谢。
  • 将 XML 作为图像发布并不是非常有用,尽管从该图像中没有任何明显的拼写错误。 (如果它是 CLOB,为什么你的专栏叫 xml_blob?)。大概您的查询显示了您期望的 CLOB 值,而仅提取的值为 null?您能否将其简化为实际重现问题的更简单示例,因为您的第一个“标题”版本没有?
  • 将其缩减为仍然显示问题的最小示例 - 删除任何不相关/在层次结构中的节点,并隐藏您不想共享的任何数据。但请检查当您运行该缩减版本时,您仍然会看到相同的问题。
  • 是的,这是一个相当重要的遗漏......即使你所说的是你的“实际 XML”。我想我应该问的。 *8-)

标签: xml oracle clob


【解决方案1】:

您更新后的 XML 有一个命名空间,这最终揭示了问题所在。您需要specify the namespace as part of the XML extraction,使用 XMLTable 方法更简单;在这种情况下,您可以将其视为默认命名空间:

select itc.element_name, x.user_classification3
from i_transaction itc
cross join xmltable(
  xmlnamespaces(default 'http://xmlns.oracle.com/apps/otm'),
    '/TenderOffer/Shipment/RATE_OFFERING/RATE_OFFERING_ROW'
  passing xmltype(itc.xml_blob)
  columns user_classification3 varchar2(10) path 'USER_CLASSIFICATION3'
) x
where itc.i_transaction_no = 31553115
and rownum = 1;

ELEMENT_NA USER_CLASS
---------- ----------
dummy      ZXF       

或使用 XMLQuery:

select itc.element_name, xmlquery(
  'declare default element namespace "http://xmlns.oracle.com/apps/otm"; (: :)
    /TenderOffer/Shipment/RATE_OFFERING/RATE_OFFERING_ROW/USER_CLASSIFICATION3/text()'
  passing xmltype(itc.xml_blob)
  returning content
) x
from i_transaction itc
where itc.i_transaction_no = 31553115
and rownum = 1;

ELEMENT_NA X                                                                               
---------- --------------------------------------------------------------------------------
dummy      ZXF                                                                             

如果您想继续使用已弃用的 extractvalue() 函数,您也可以将命名空间作为参数提供给它,同样是 as shown in the documentation

select itc.element_name,
  extractvalue(xmltype(xml_blob),
    '/TenderOffer/Shipment/RATE_OFFERING/RATE_OFFERING_ROW/USER_CLASSIFICATION3/text()',
    'xmlns="http://xmlns.oracle.com/apps/otm"')
from i_transaction itc where itc.i_transaction_no = 31553115 and rownum = 1;

【讨论】:

    【解决方案2】:

    在您的代码中,您使用 XML_BLOB 作为变量 - 所以我假设了 BLOB 数据类型,它需要转换为 CLOB。但是,如果您有 CLOB 值,那么您可以跳过使用 BLOB_TO_CLOB 函数:

    Oracle 11 设置

    CREATE OR REPLACE FUNCTION BLOB_TO_CLOB( b BLOB )
    RETURN CLOB 
    IS
      c            CLOB;
      n            INTEGER     := 1;
      w   CONSTANT PLS_INTEGER := 32767;
      len CONSTANT INTEGER     := LENGTH( b );
    BEGIN
      IF b IS NULL THEN
        RETURN NULL;
      END IF;
    
      IF len = 0 THEN
        RETURN EMPTY_CLOB();
      END IF;
    
      DBMS_LOB.CREATETEMPORARY( c, TRUE );
      WHILE ( n + w <= len ) LOOP
        DBMS_LOB.WRITEAPPEND( c, w, UTL_RAW.CAST_TO_VARCHAR2( DBMS_LOB.SUBSTR( b, w, n ) ) );
        n := n + w;
      END LOOP;
      DBMS_LOB.WRITEAPPEND( c, len - n + 1, UTL_RAW.CAST_TO_VARCHAR2( DBMS_LOB.SUBSTR( b, len - n + 1, n ) ) );
      RETURN c;
    END;
    /
    
    CREATE TABLE blob_test ( value BLOB );
    
    INSERT INTO blob_test VALUES (
      UTL_RAW.CAST_TO_RAW(
        '<Header>' ||
          '<SecondHeader>' ||
            '<ThirdHeader>' ||
              '<FourthHeader>' ||
                '<Value1>abcd</Value1>' ||
                '<Value2>xyz</Value2>' ||
                '<Value3>abxy</Value3>' ||
              '</FourthHeader>' ||
            '</ThirdHeader>' ||
          '</SecondHeader>' ||
        '</Header>'
      )
    );
    

    查询

    EXTRACTEXTRACTVALUE 已弃用 - 请改用 XMLTABLE

    SELECT Value1, Value2, Value3
    FROM   blob_test b
           CROSS JOIN
           XMLTABLE(
             '/Header/SecondHeader/ThirdHeader/FourthHeader'
             PASSING XMLTYPE( BLOB_TO_CLOB( b.value ) )
             COLUMNS Value1 VARCHAR2(50) PATH 'Value1/text()',
                     Value2 VARCHAR2(50) PATH 'Value2/text()',
                     Value3 VARCHAR2(50) PATH 'Value3/text()'
           ) x;
    

    输出

    VALUE1 VALUE2 VALUE3
    ------ ------ ------
    abcd   xyz    abxy
    

    查询 2

    如果您确实想使用 EXTRACTVALUE,您可以从 XPath 中删除 /text(),因为 EXTRACTVALUE 会为您执行此操作(但它仍然可以在那里使用)并将 BLOB 转换为CLOB:

    SELECT EXTRACTVALUE(
             XMLTYPE( BLOB_TO_CLOB( value ) ), 
             '/Header/SecondHeader/ThirdHeader/FourthHeader/Value3'
           )
    FROM   blob_test
    

    查询 - 更新

    @AlexPoole 简化。不需要调用BLOB_TO_CLOB,因为XMLTYPE constructor 可以采用BLOB 和字符集ID:

    SELECT Value1, Value2, Value3
    FROM   blob_test b
           CROSS JOIN
           XMLTABLE(
             '/Header/SecondHeader/ThirdHeader/FourthHeader'
             PASSING XMLTYPE( b.value, NLS_CHARSET_ID('UTF8') )
             COLUMNS Value1 VARCHAR2(50) PATH 'Value1/text()',
                     Value2 VARCHAR2(50) PATH 'Value2/text()',
                     Value3 VARCHAR2(50) PATH 'Value3/text()'
           ) x;
    

    【讨论】:

    • 有点小问题,因为 OP 指出该列是 CLOB,尽管名称 (!),但只要您知道字符集,您就不必先转换 BLOB传递给 XMLType 构造函数 - 例如xmltype(xml_blob, nls_charset_id('UTF8')).
    • @AlexPoole 在第一段中,我确实解决了该差异,并选择解决两个可能版本中更复杂的问题,并添加了注释,对于CLOB,您可以删除对@987654346 的调用@。但是,很高兴知道XMLType 的附加参数。
    • 是的,如果它 BLOB,它只是一个替代方案 - 我只是补充说,更复杂的场景仍然不一定需要blob_to_clob 函数,顺便说一句使用 DB 字符集。当然,无论如何,它都是有用的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-28
    • 2012-04-28
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 2019-07-05
    • 2012-11-26
    相关资源
    最近更新 更多