Oracle 11g R2 - dbms_xmldom:需要重复将DOMDocumentFragment副本附加到DOMDocument中的不同位置

时间:2016-08-25 15:45:04

标签: oracle plsql oracle11gr2 xmldom

我填充DOMDocumentFragment,目的是将其内容复制到目标DOMDocument中的多个位置。

我已经尝试了几乎所有我能想到的东西来实现这一目标,但它是一个史诗般的失败案例。以下简化的工作代码说明了我尝试过的一种方法:

declare
  vTargetDoc         dbms_xmldom.DOMDocument;
  vFragDoc           dbms_xmldom.DOMDocument;
  vFrag              dbms_xmldom.DOMDocumentFragment;
  vAttachPointNodes  dbms_xmldom.DOMNodeList;
  vElt               dbms_xmldom.DOMElement;
  vTmpN              dbms_xmldom.DOMNode; 
begin
  -- create the target document
  vTargetDoc  := dbms_xmldom.newDOMDocument(xmltype('<TargetDoc><AttachPoint></AttachPoint><AttachPoint></AttachPoint></TargetDoc>'));
  -- create the source document to contain the fragment to be attached repeatedly
  vFragDoc    := dbms_xmldom.newDOMDocument();
  -- create the fragment
  vFrag       := dbms_xmldom.createDocumentFragment(vFragDoc);
  -- append element "A" to the fragment
  vElt        := dbms_xmldom.createElement(vFragDoc,'A');
  vTmpN       := dbms_xmldom.appendChild(dbms_xmldom.makeNode(vFrag),dbms_xmldom.makeNode(vElt));
  -- identify all the attach points in the target document
  vAttachPointNodes := dbms_xslprocessor.selectNodes(dbms_xmldom.makeNode(dbms_xmldom.getDocumentElement(vTargetDoc))
                                                    ,'/TargetDoc/AttachPoint'
                                                    );
  -- iterate through the attachpoints
  for i in 0 .. dbms_xmldom.getLength(vAttachPointNodes) - 1 loop
    -- import and attach the fragment to the current attachpoint
    vTmpN := dbms_xmldom.appendChild(dbms_xmldom.item(vAttachPointNodes,i)
                                    ,dbms_xmldom.importNode(vTargetDoc
                                                           ,dbms_xmldom.makeNode(vFrag)
                                                           ,true
                                                           )
                                    );
  end loop;
  -- print out the resultant target document XML
  dbms_output.put_line(dbms_xmldom.getxmltype(vTargetDoc).getclobval());
end;

上面代码中值得注意的项目是:

  1. 我在不同的文档中创建片段
  2. 在每个附加点上,我将片段作为节点导入(具有deep = true)
  3. 此方法的目的是使用importNode从源文档中复制片段的内容,因为我需要将其附加到目标文档中。

    好消息是它确实成功地将导入片段的内容复制到每个所需的附加点。

    坏消息是它还在文档的末尾附加了导入片段的副本,如以下说明性输出所示:

    <TargetDoc>
      <AttachPoint>
        <A/>             EXPECTED
      </AttachPoint>
      <AttachPoint>
        <A/>             EXPECTED
      </AttachPoint>
    </TargetDoc>
    <A/>                 UNEXPECTED
    <A/>                 UNEXPECTED
    

    (附加在文档末尾的2个FragmentContents副本是意外的)

    我无法弄清楚为什么使用这种方法创建重复项,我也找不到任何其他有效的方法。

    非常感谢任何帮助。谢谢!

1 个答案:

答案 0 :(得分:1)

问题似乎是对dbms_xmldom.makeNode(vFrag)的重复调用;你每次围绕循环再次这样做,这会创建另一个新节点,并且在那时你不会调用appendChild()它似乎把它贴在某个看起来有点随机的地方。 / p>

您可以参考第一个电话的结果vTmpN,而不是:

  for i in 0 .. dbms_xmldom.getLength(vAttachPointNodes) - 1 loop
    -- import and attach the fragment to the current attachpoint
    vTmpN := dbms_xmldom.appendChild(dbms_xmldom.item(vAttachPointNodes,i)
                                    ,dbms_xmldom.importNode(vTargetDoc
                                                           --,dbms_xmldom.makeNode(vFrag)
                                                           ,vTmpN
                                                           ,true
                                                           )
                                    );
  end loop;

产生:

<TargetDoc>
  <AttachPoint>
    <A/>
  </AttachPoint>
  <AttachPoint>
    <A/>
  </AttachPoint>
</TargetDoc>

在这个示例中,您重新分配vTmpN似乎并不重要 - 下一次循环仍然保留您想要的节点。您可能更喜欢使用单独的变量来保证安全(或更清晰)。