Как скопировать структуру подузла из одного файла XML в другой файл XML (объединить два файла XML)? - PullRequest
2 голосов
/ 09 июля 2020

У меня есть следующие два файла XML:

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>

В Delphi я хотел бы добавить полную структуру <node1>...</node1> File2 в File1, переименованную в <node2>...</node2>. Результат должен выглядеть так:

<?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>

Я уже спросил, как извлечь блок <node1>...</node1> в вопросе Как извлечь внутренний текст и XML узла в виде строки? (что действительно было проблемой XY, извините за это), и я мог бы найти решение, манипулируя XML как строками.

Но я полагаю, что может быть лучшее решение, работающее непосредственно с XML функциональность. Итак, как я могу реализовать это в Delphi 10?

Ответы [ 2 ]

3 голосов
/ 09 июля 2020

После того, как вы разобрали файлы XML на объекты TXMLDocument / IXMLDocument, клонировать / перемещать IXMLNode* 1009 довольно просто. * объекты из одного документа в другой (см. IXMLNode.CloneNode() или IXMLNodeList.Add() и IXMLNodeList.Remove()). Хотя вы не можете переименовать узел, вы можете создать новый узел с желаемым именем (см. IXMLNode.AddChild()), а затем клонировать / переместить дочерние элементы старого узла под новым узлом.

Вы не должны использовать строки XML для этих задач. Вместо этого манипулируйте деревом DOM. Таким образом, вы получите IXMLNode для <node1> в File2, добавьте новый IXMLNode для <node2> в File1, а затем клонируйте / переместите <subnode1> и <subnode2> из IXMLNode в File2 в IXMLNode в файле 1.

При этом, почему ваши элементы сначала называются последовательно? <node>, <subnode>, <value>, и т.д. c будет вполне достаточно. Вы можете иметь несколько <node> s, несколько <subnode> s, несколько <value> в одном документе по мере необходимости. XML позволяет использовать повторяющиеся имена элементов. На самом деле вам не нужно использовать последовательные числа в именах элементов, например:

<?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>

Если вам действительно нужно различать по числам, вы можете вместо этого использовать атрибуты, например:

<?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 голосов
/ 09 июля 2020

Вы можете использовать IXMLNode.CloneNode().

Вот полный пример:

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;
...