PL/SQL - XML Clob 错误

Posted

技术标签:

【中文标题】PL/SQL - XML Clob 错误【英文标题】:PL/SQL - XML clob error 【发布时间】:2017-11-17 21:22:27 【问题描述】:

我正在尝试测试一个以 xml CLOB 作为参数的 PL/SQL 过程

PROCEDURE example_proc(ex_xml CLOB) IS
BEGIN

/* Find the second < (skip over declaration) */
ln_position := instr(pc_shipment_xml, '<', 1, 2);
/* Find the space after the first tag */
ln_position := instr(pc_shipment_xml, ' ', ln_position, 1);
/* Set the first part of the XML clob */
lc_shipment_xml := substr(pc_shipment_xml, 1, ln_position - 1);
/* Skip the namespace */
ln_position     := instr(pc_shipment_xml, '>', ln_position, 1);
lc_shipment_xml := lc_shipment_xml || substr(pc_shipment_xml, ln_position);

/* Set the XML type */
lx_shipment_xml := xmltype(lc_shipment_xml); --RIGHT HERE IS WHERE IT ERRORS OUT

这是我传入的 xml(作为 ex_xml clob 参数):

    xml := 
'<Shipment>
  <OrderNumber>00000</OrderNumber>
   <ShipmentLines>
    <ShipmentLine>
      <OrderDetailId>000000</OrderDetailId>
      <LineNumber>0</LineNumber>
      <ItemId>00000</ItemId>
      <UnitId>0000000</UnitId>
      <BaseUom>X</BaseUom>
      <Quantity1>000</Quantity1>
    </ShipmentLine>
  </ShipmentLines>
</Shipment>';

它在最后一行出错:

ORA-19202: Error occurred in XML processing
LPX-002255: end-element tag "ShipmentLines" does not match start-element tag "Shipment"

请原谅我的无知,但这是我第一次在 PL/SQ 中使用 XML,我是否遗漏了格式?据我所见,我正在正确打开和关闭我的标签。任何意见都表示赞赏。

【问题讨论】:

您真的尝试使用instrsubstr 等修改XML 文档吗?看看XML Functions 【参考方案1】:

运行你的代码

declare
  pc_shipment_xml CLOB := '<Shipment>
  <OrderNumber>00000</OrderNumber>
   <ShipmentLines>
    <ShipmentLine>
      <OrderDetailId>000000</OrderDetailId>
      <LineNumber>0</LineNumber>
      <ItemId>00000</ItemId>
      <UnitId>0000000</UnitId>
      <BaseUom>X</BaseUom>
      <Quantity1>000</Quantity1>
    </ShipmentLine>
  </ShipmentLines>
</Shipment>';
  lc_shipment_xml varchar2(2000);
  ln_position integer;
BEGIN
  /* Find the second < (skip over declaration) */
  ln_position := instr(pc_shipment_xml, '<', 1, 2);
  /* Find the space after the first tag */
  ln_position := instr(pc_shipment_xml, ' ', ln_position, 1);
  /* Set the first part of the XML clob */
  lc_shipment_xml := substr(pc_shipment_xml, 1, ln_position - 1);
  /* Skip the namespace */
  ln_position     := instr(pc_shipment_xml, '>', ln_position, 1) + 1;
  lc_shipment_xml := lc_shipment_xml || substr(pc_shipment_xml, ln_position);
  dbms_output.put_line(lc_shipment_xml);
end;
/

给出以下输出:

<Shipment>
  <OrderNumber>00000</OrderNumber>

    <ShipmentLine>
      <OrderDetailId>000000</OrderDetailId>
      <LineNumber>0</LineNumber>
      <ItemId>00000</ItemId>
      <UnitId>0000000</UnitId>
      <BaseUom>X</BaseUom>
      <Quantity1>000</Quantity1>
    </ShipmentLine>
  </ShipmentLines>
</Shipment>

所以看起来您正在剥离开始 ShipmentLines 标记,而不是结束标记

如果您知道要删除的标签的名称,则可以更简单地使用

lc_shipment_xml := regexp_replace(pc_shipment_xml, '</?ShipmentLines>');

或按位置获取标签:

l_tag := regexp_substr(pc_shipment_xml, '<(\w+)>',1,3,'i',1);
lc_shipment_xml := regexp_replace(pc_shipment_xml, '</?' || l_tag || '>');

更好的方法是使用 xml 函数,如下所示:

declare
  pc_shipment_xml CLOB := '<Shipment>
  <OrderNumber>00000</OrderNumber>
  <ShipmentLines>
    <ShipmentLine>
      <OrderDetailId>000000</OrderDetailId>
      <LineNumber>0</LineNumber>
      <ItemId>00000</ItemId>
      <UnitId>0000000</UnitId>
      <BaseUom>X</BaseUom>
      <Quantity1>000</Quantity1>
    </ShipmentLine>
  </ShipmentLines>
</Shipment>';
  lx_shipment_xml xmltype := xmltype(pc_shipment_xml);
  lx_shipline_xml xmltype := xmltype(pc_shipment_xml);
  lc_shipment_xml varchar2(2000);
BEGIN
  /* Set the XML type */
    select extract(lx_shipment_xml, '/Shipment/ShipmentLines/ShipmentLine') into lx_shipline_xml from dual;
    select deletexml(lx_shipment_xml, '/Shipment/ShipmentLines') into lx_shipment_xml from dual;
    select insertxmlafter(lx_shipment_xml, '/Shipment/OrderNumber', lx_shipline_xml) into lx_shipment_xml from dual;
    select xmlserialize(content lx_shipment_xml) into lc_shipment_xml from dual;
    dbms_output.put_line(lc_shipment_xml);
end;
/

【讨论】:

【参考方案2】:

我解析 xml 的方式需要将 &lt;?xml version="1.0"?&gt; 放在 clob 的开头。解析方法不是我自己的代码,所以改变我做的方式不是一个选择。谢谢

【讨论】:

以上是关于PL/SQL - XML Clob 错误的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 PL/SQL:ORA-00932:不一致的数据类型:预期的 CLOB 得到了 -

使用 PL SQL 提取基于属性的 XML

插入 CLOB 列时出错:ORA-06502:PL/SQL:数字或值错误

如何在 PL/SQL 中使用 FOR LOOP 从具有相同标签的 xml clob 中提取值

将PL/SQL代码封装在机灵的包中

使用 PL/SQL 解析 XML 输出 html 中特定标签的内容