在 Oracle 中不使用命名空间的 XMLTable

XMLTable without using namespaces in Oracle

我正在尝试使用 PL/SQL 中的 XMLTable 提取 xml 值。

DECLARE
xdata XMLType := XMLType(
    '<?xml version="1.0" encoding="UTF-8"?>
            <stusMsg xmlns="http://www.my.namespace.com/src">
            <messageHeader>
              <sourceSystem>PFS</sourceSystem>
              <originatingSystem>MRTI HKH</originatingSystem>
            </messageHeader>
            <messageDetail>
            <TradeRef>1033796</TradeRef>
            <TradeRefType>Ticket</TradeRefType>
            <Company>MY_CMPY</Company>
            <TradeGREF></TradeGREF>
            <TradeType>TRD</TradeType>
            <PriorityType>CRS</PriorityType>
            <Priority>1</Priority>
            </messageDetail>
            </stusMsg>');

CURSOR get_data(x XMLType) IS
SELECT * 
FROM XMLTABLE(xmlnamespaces(default 'http://www.my.namespace.com/src'),
   '/stusMsg/messageDetail'
   passing x
           COLUMNS 
           TradeRef      VARCHAR2(30)    PATH 'TradeRef',
           TradeRefType  VARCHAR2(30)    PATH 'TradeRefType');
BEGIN

FOR rec IN get_data(xdata) LOOP
  dbms_output.put_line(rec.TradeRef);
  dbms_output.put_line(rec.TradeRefType);
  END LOOP;
END;

如果我不在 XMLTABLE 中使用 xmlnamespaces(default 'http://www.my.namespace.com/src') 并且 xml (xdata) 中存在命名空间,则不会提取值。

有没有办法告诉 XMLTABLE 忽略命名空间?这样程序就不会依赖于 xmlnamespaces

如果只有默认命名空间,您可以从文档根目录中删除 xmlns 属性,而不是试图忽略命名空间:

DECLARE
  v_dom DBMS_XMLDOM.DOMDocument;
  xdata XMLTYPE := XMLTYPE('<?xml version="1.0" encoding="UTF-8"?>
    <stusMsg xmlns="http://www.my.namespace.com/src">
    <messageHeader>
      <sourceSystem>PFS</sourceSystem>
      <originatingSystem>MRTI HKH</originatingSystem>
    </messageHeader>
    <messageDetail>
    <TradeRef>1033796</TradeRef>
    <TradeRefType>Ticket</TradeRefType>
    <Company>MY_CMPY</Company>
    <TradeGREF></TradeGREF>
    <TradeType>TRD</TradeType>
    <PriorityType>CRS</PriorityType>
    <Priority>1</Priority>
    </messageDetail>
    </stusMsg>');
  CURSOR get_data(x XMLType) IS
    SELECT * 
    FROM XMLTABLE(
           '/stusMsg/messageDetail'
           passing x
           COLUMNS 
             TradeRef      VARCHAR2(30)    PATH 'TradeRef',
             TradeRefType  VARCHAR2(30)    PATH 'TradeRefType'
         );
BEGIN
  v_dom  := DBMS_XMLDOM.NEWDOMDOCUMENT(xdata);
  DBMS_XMLDOM.REMOVEATTRIBUTE(
    DBMS_XMLDOM.GETDOCUMENTELEMENT(v_dom),
    'xmlns'
  );
  xdata := DBMS_XMLDOM.GETXMLTYPE(v_dom);
  
  FOR rec IN get_data(xdata) LOOP
    dbms_output.put_line(rec.TradeRef);
    dbms_output.put_line(rec.TradeRefType);
  END LOOP;
END;
/

输出:

1033796
Ticket

db<>fiddle here

如果您真的不想遵守 XML 文档中的命名空间,您可以对所有节点引用使用通配符:

SELECT * 
FROM XMLTABLE(
   '/*:stusMsg/*:messageDetail'
   passing x
           COLUMNS 
           TradeRef      VARCHAR2(30)    PATH '*:TradeRef',
           TradeRefType  VARCHAR2(30)    PATH '*:TradeRefType');

db<>fiddle

但这似乎不太理想;如果可以的话,我会正确使用它们。