How to copy a sub node structure from one XML file to another XML file (merge two XML files)?

吃可爱长大的小学妹 提交于 2020-08-08 07:02:13

问题


I have the following two XML files:

File1

<?xml version="1.0"?>
<main>
  <node1>
    <subnode1>
      <value1>101</value1>
      <value2>102</value2> 
      <value3>103</value3> 
    </subnode1>
    <subnode2>
      <value1>501</value1>
      <value2>502</value2> 
      <value3>503</value3> 
    </subnode2>
  </node1>
</main>

File2

<?xml version="1.0"?>
<main>
  <node1>
    <subnode1>
      <value1>454</value1>
      <value2>471</value2> 
      <value3>498</value3> 
    </subnode1>
    <subnode2>
      <value1>723</value1>
      <value2>645</value2> 
      <value3>823</value3> 
    </subnode2>
  </node1>
</main>

In Delphi I would like to add the complete <node1>...</node1> structure of File2 to File1 renamed as <node2>...</node2>. So the result should look like this:

<?xml version="1.0"?>
<main>
  <node1>
    <subnode1>
      <value1>101</value1>
      <value2>102</value2> 
      <value3>103</value3> 
    </subnode1>
    <subnode2>
      <value1>501</value1>
      <value2>502</value2> 
      <value3>503</value3> 
    </subnode2>
  </node1>
  <node2>
    <subnode1>
      <value1>454</value1>
      <value2>471</value2> 
      <value3>498</value3> 
    </subnode1>
    <subnode2>
      <value1>723</value1>
      <value2>645</value2> 
      <value3>823</value3> 
    </subnode2>
  </node2>
</main>

I asked already how to extract the <node1>...</node1> block in the question How to extract the inner text and XML of node as string? (which was indeed a XY-problem, sorry about that) and I could work out a solution with manipulating the XML as strings.

But I suppose there might be a better solution working directly with the XML functionality. So how could I implement this in Delphi 10?


回答1:


Once you have parsed the XML files into TXMLDocument/IXMLDocument objects, it is fairly trivial to clone/move IXMLNode objects from one document to the other (see IXMLNode.CloneNode(), or IXMLNodeList.Add() and IXMLNodeList.Remove()). Although you can't rename a node, you can create a new node with the desired name (see IXMLNode.AddChild()), and then clone/move the old node's children underneath the new node.

You should not be using XML strings for these tasks. Manipulate the DOM tree instead. So, you would get the IXMLNode for <node1> in File2, add a new IXMLNode for <node2> in File1, and then clone/move <subnode1> and <subnode2> from the IXMLNode in File2 to the IXMLNode in File1.


That being said, why are your elements named sequentially to begin with? <node>, <subnode>, <value>, etc would suffice just fine. You can have multiple <node>s, multiple <subnode>s, multiple <value>'s in one document as needed. XML is good about using repeated element names. You don't really need to use sequential numbers in element names, eg:

<?xml version="1.0"?>
<main>
  <node>
    <subnode>
      <value>101</value>
      <value>102</value> 
      <value>103</value> 
    </subnode>
    <subnode>
      <value>501</value>
      <value>502</value> 
      <value>503</value> 
    </subnode>
  </node>
  <node>
    <subnode>
      <value>454</value>
      <value>471</value> 
      <value>498</value> 
    </subnode>
    <subnode>
      <value>723</value>
      <value>645</value> 
      <value>823</value> 
    </subnode>
  </node>
</main>

If you really needed to differentiate by numbers, you could use attributes instead, eg:

<?xml version="1.0"?>
<main>
  <node id="1">
    <subnode id="1">
      <value id="1">101</value>
      <value id="2">102</value> 
      <value id="3">103</value> 
    </subnode>
    <subnode id="2">
      <value id="1">501</value>
      <value id="2">502</value> 
      <value id="3">503</value> 
    </subnode>
  </node>
  <node id="2">
    <subnode id="1">
      <value id="1">454</value>
      <value id="2">471</value> 
      <value id="3">498</value> 
    </subnode>
    <subnode id="2">
      <value id="1">723</value>
      <value id="2">645</value> 
      <value id="3">823</value> 
    </subnode>
  </node>
</main>



回答2:


You can use IXMLNode.CloneNode().

Here is a complete example:

uses XMLIntf, XMLDoc, xmldom;

procedure Test;
var
    XML1, XML2: DOMString;
    Doc1, Doc2: IXMLDocument;
    NewNode, Node1: IXMLNode;
    i: integer;
begin
    XML1 := '<?xml version="1.0"?><main><node1><subnode>1</subnode></node1></main>';
    Doc1 := LoadXMLData(XML1);
    NewNode := Doc1.DocumentElement.AddChild('node2');

    XML2 := '<?xml version="1.0"?><main><node1><subnode>2</subnode></node1></main>';
    Doc2 := LoadXMLData(XML2);
    Node1 := Doc2.DocumentElement.ChildNodes['node1'];

    // Clone nodes from Doc2 to Doc1
    for i := 0 to Node1.ChildNodes.Count - 1 do
        NewNode.ChildNodes.Add(Node1.ChildNodes[i].CloneNode(true));

    Doc1.SaveToFile('merged.xml');
end;


来源:https://stackoverflow.com/questions/62820953/how-to-copy-a-sub-node-structure-from-one-xml-file-to-another-xml-file-merge-tw

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!