问题
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