Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   XML (https://www.delphipraxis.net/46-xml/)
-   -   Delphi (unbekannte) XML Dateien zusammenführen bzw. mergen (https://www.delphipraxis.net/140616-unbekannte-xml-dateien-zusammenfuehren-bzw-mergen.html)

padavan 22. Sep 2009 09:06


(unbekannte) XML Dateien zusammenführen bzw. mergen
 
Hallo,

Wie kann ich zwei mir unbekannte XML-Dateien zusammenführen (mergen)?
(Abgesehen vom Root-Knoten, der heißt immer gleich. Spielt vielleicht eine Rolle für den ein oder anderen Lösungsansatz)

Hier gibt es ein Beispiel von Microsoft, habe Versucht es auf Delphi um zu schreiben, aber es will nicht funktionieren.

Delphi-Quellcode:
procedure XMLmergeBasefileWithAnotherFile(aBaseXMLfile: string; aAnotherXMLfile: string; aTargetFile: string);
var
  XmldocBase   : DOMDocument;
  RootBase     : IXMLDOMNode;
  NodeBase     : IXMLDOMNode;
  ListBase     : IXMLDOMNodeList;

  XmldocAnother : DOMDocument;
  RootAnother  : IXMLDOMNode;
  NodeAnother  : IXMLDOMNode;
  ListAnother  : IXMLDOMNodeList;

  i, j         : integer;
begin



  // -- Base file laden --
  XmlDocBase := CoDOMDocument.Create;
  if not xmlDocBase.load(aBaseXMLfile) then exit;
  RootBase := XmlDocBase.documentElement;
  ListBase := RootBase.childNodes;

  // -- Another file laden --
  XmldocAnother := CoDOMDocument.Create;
  if not XmldocAnother.load(aAnotherXMLfile) then exit;
  RootAnother := XmlDocBase.documentElement;
  ListAnother := RootAnother.childNodes;


  NodeBase := RootBase.firstChild;
  NodeAnother := RootAnother.firstChild;


  while NodeAnother.NextSibling <> nil do
  begin
    NodeBase.appendChild(NodeAnother);


    NodeAnother := NodeAnother.NextSibling;
  end;



  // -- gemergte Base XML speichern --
  XmldocBase.save(aTargetFile);


end;
Gibt es noch eine andere Möglichkeit?


Ich nutze zur Zeit Delphi 6 Enterprise, mir steht also das TXMLDocument zur Verfügung, und ich habe die MSXML_TLB importiert.

Vielen Dank schon mal

Padavan

himitsu 22. Sep 2009 09:38

Re: (unbekannte) XML Dateien zusammenführen bzw. mergen
 
Delphi-Quellcode:
function XMLmergeBasefileWithAnotherFile(const aBaseXMLfile, aAnotherXMLfile, aTargetFile: String): Boolean;
var
  XmldocBase, XmldocAnother      : DOMDocument;
  NodeBase, NodeAnother, NodeNext : IXMLDOMNode;
begin
  Result := False;

  XmlDocBase := CoDOMDocument.Create;
  if not xmlDocBase.load(aBaseXMLfile) then exit;

  XmldocAnother := CoDOMDocument.Create;
  if not XmldocAnother.load(aAnotherXMLfile) then exit;

  NodeBase := XmlDocBase.documentElement;
  NodeAnother := XmldocAnother.documentElement.firstChild;

  while Assigned(NodeAnother) do
  begin
    NodeNext := NodeAnother.NextSibling;
    NodeBase.appendChild(NodeAnother);
    NodeAnother := NodeNext;
  end;

  XmldocBase.save(aTargetFile);
  Result := True;
end;
Delphi-Quellcode:
while NodeAnother.NextSibling <> nil do
NodeAnother und nicht NodeAnother.NextSibling, da sonst immer der letze Knoten vergessen würde,
man will ja diesen Knoten einfügen und da ist es nur wichtig, daß dieser existiert ... der nachvolgende ist erstmal egal und wird dann im nächsten Durchgang geprüft

ListBase und ListAnother wurden nie verwendet

Delphi-Quellcode:
NodeBase.appendChild(NodeAnother);
NodeAnother := NodeAnother.NextSibling;
wenn NodeAnother auf das andere Dokument übertragen wurde, hat er keinen Nachfolger mehr, da er er als letzes eingefügt wurde und der "alte" Nachfolger im anderen Dokument verblieb ... also erst den Nachfolger merken und dann den Knoten übertragen

Delphi-Quellcode:
RootAnother := XmlDocBase.documentElement; <<<<<<<<<<<
ListAnother := RootAnother.childNodes;
...
while NodeAnother.NextSibling <> nil do
und daß deine Schleife nie loslief bzw. eine Exception warf, lag auch daran
> RootAnother und XmlDocBase ... fällt dir da was auf?

[edit] die Prozedur noch schnell in eine Funktion umgewandelt :angel2:

padavan 22. Sep 2009 10:37

Re: (unbekannte) XML Dateien zusammenführen bzw. mergen
 
Wow, Vielen Dank.


Aber vielleicht hätte ich vorher noch genauer sagen sollen, was ich brauche. :oops:

Es sollen zwei XML Dateien miteinander verbunden werden, aber, bereits vorhandene Knoten sollen vorhanden bleiben, bzw. bei Änderungen eines "Wertes" geändert werden.

aBaseXMLfile:

Delphi-Quellcode:
<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
   <nodes>
      <node>
         <Kenn>Kennung1</Kenn>
         <Wert>Wert1</Wert>
      </node>
      <node>
         <Kenn>Kennung2</Kenn>
         <Wert>Wert2</Wert>
      </node>
      <node>
         <Kenn>Kennung3</Kenn>
         <Wert>Wert3</Wert>
      </node>
      <node>
         <Kenn>Kennung4</Kenn>
         <Wert>Wert4</Wert>
      </node>
   </nodes>
</root>

aAnotherXMLfile:

Delphi-Quellcode:
<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
   <nodes>
      <node>
         <Kenn>Kennung1</Kenn>
         <Wert>Wert1</Wert>
      </node>
      <node>
         <Kenn>Kennung2</Kenn>
         <Wert>Wert22222222</Wert>
      </node>
      <node>
         <Kenn>Kennung5</Kenn>
         <Wert>Wert5</Wert>
      </node>
   </nodes>
</root>

soll werden zu
aTargetFile:

Delphi-Quellcode:
<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
   <nodes>
      <node>
         <Kenn>Kennung1</Kenn>  
         <Wert>Wert1</Wert>         <?bleibt?>
      </node>
      <node>
         <Kenn>Kennung2</Kenn>
         <Wert>Wert22222222</Wert>  <?wird ueberschrieben?>
      </node>
      <node>
         <Kenn>Kennung3</Kenn>      <?bleibt?>
         <Wert>Wert3</Wert>
      </node>
      <node>
         <Kenn>Kennung4</Kenn>      <?bleibt?>
         <Wert>Wert4</Wert>
      </node>
      <node>
         <Kenn>Kennung5</Kenn>      <?wurde hinzugefuegt?>
         <Wert>Wert5</Wert>
      </node>
   </nodes>
</root>
Bei der von Microsoft angesetzen Lösung (und von himitsu umgesetzen Lösung) werden die Unterknoten nicht berücksichtigt, sondern einfach neue angelegt.
Ich hatte das aber auf der Microsoftseite so verstanden, dass es genau dieses können soll. Ok, dass Beispiel war nicht in der Art gestalltet.

Geht das denn überhaupt?

Edit:
Beim drübernachdenken kommt mir, dass die XML Dateien dann nicht unbekannt sein dürfen. Z.B. der Unterkenner "Kenn" müsste ja bekannt sein, damit die Parameter zugordnet werden können.
Obwohl, wenn man innerhalb der Schleife eine rekursive Unterschleife einbaut, sollte man auch unbekannte Unterknoten herausfinden....jetz bin ich raus

himitsu 22. Sep 2009 11:12

Re: (unbekannte) XML Dateien zusammenführen bzw. mergen
 
Jupp, da muß der Aufbau schon bekannt sein.

Also du gehst Another wie bekannt durch, holst dir jeweils den Inhalt des untergeordneten Kenn
und nun mußt du schauen ob in Base ein Knoten mir Kenn={Text} vorhanden ist,

- wenn ja
inhalt dieses Knotens in Another löschen und den Inhalt von Base rüberkopieren
oder knoten ganz löschen und dann das Selbe wie in "nein" machen

- wenn nein
neuen Knoten erstellen und Inhalt kopieren
oder Knoten wie vorhin einfach übertragen

padavan 22. Sep 2009 14:29

Re: (unbekannte) XML Dateien zusammenführen bzw. mergen
 
Zitat:

- wenn nein
neuen Knoten erstellen und Inhalt kopieren
oder Knoten wie vorhin einfach übertragen
Zitat:

oder Knoten wie vorhin einfach übertragen
Ne, das geht leider nicht, da das Ergebniss von der bisherigen Routine dieses Ergebniss bringt:

Delphi-Quellcode:
<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
   <nodes>
      <node>
         <Kenn>Kennung1</Kenn>
         <Wert>Wert1</Wert>
      </node>
      <node>
         <Kenn>Kennung2</Kenn>
         <Wert>Wert2</Wert>
      </node>
      <node>
         <Kenn>Kennung3</Kenn>
         <Wert>Wert3</Wert>
      </node>
      <node>
         <Kenn>Kennung4</Kenn>
         <Wert>Wert4</Wert>
      </node>
   </nodes>
   <nodes> <?dieser sollte eigentlich nicht mehr angelegt werden?>
      <node>
         <Kenn>Kennung1</Kenn>
         <Wert>Wert1</Wert>
      </node>
      <node>
         <Kenn>Kennung2</Kenn>
         <Wert>Wert22222222</Wert>
      </node>
      <node>
         <Kenn>Kennung5</Kenn>
         <Wert>Wert5</Wert>
      </node>
   </nodes>
</root>
Der erste Unterknoten von <root> ist hier <nodes>.
Dieser hätte nicht noch einmal neu angelegt werden sollen, sondern die <node> Knoten hätten in den bestehenden <nodes> Knoten eingefügt werden sollen.

Bin für Anregungen dankbar, probiere aber mal mein Glück....

padavan 23. Sep 2009 14:24

Re: (unbekannte) XML Dateien zusammenführen bzw. mergen
 
O mann,
ich komm nicht weiter.

Mein erstes Problem ist nocht nicht gelöst, siehe letzten Beitrag. Die Datei wurde nicht nach meiner Vorstellung gemergt.

Da ich gar nicht weitergekommen bin, habe ich sogar den ersten Knoten mit Namen angesprochen. Die Überschrift "(unbekannte) XML...." stimmt dann zwar nicht mehr, aber das wäre nicht unbedingt das Problem.
Delphi-Quellcode:
    if NodeBase.selectSingleNode('nodes/node[Kenn]').firstChild.text
       = NodeAnother.selectSingleNode('nodes/node[Kenn]').firstChild.text
    then
    begin
      // hier fehlt der Geist
    end;

Dann noch eine Frage. Kann man einen Knoten mitsamt seiner Unterknoten kopieren, ohne das ich die Namen der Knoten wissen muss?

Delphi-Quellcode:

kopiere:

      <node>
         <Kenn>Kennung1</Kenn> <?relevantes Erkennungsmerkmal?>
         <Wert>Wert1</Wert>
         ....
      </node>
Hüüülfe

himitsu 23. Sep 2009 14:53

Re: (unbekannte) XML Dateien zusammenführen bzw. mergen
 
Wie um Himmels Willen, wie löscht man bei diesem Ding die alten Nodes?

Aber im Prinzip geht's, auch wenn man via XPath oder so, bestimmt kürzeren Code hinbekommt
Delphi-Quellcode:
function XMLmergeBasefileWithAnotherFile(const aBaseXMLfile, aAnotherXMLfile, aTargetFile: String): Boolean;
var
  XmldocBase, XmldocAnother      : DOMDocument;
  NodeBase, NodeAnother, NodeNext : IXMLDOMNode;
  i, i2                           : Integer;
begin
  Result := False;

  XmlDocBase := CoDOMDocument.Create;
  if not xmlDocBase.load(aBaseXMLfile) then exit;

  XmldocAnother := CoDOMDocument.Create;
  if not XmldocAnother.load(aAnotherXMLfile) then exit;

  NodeBase := XmlDocBase.documentElement.firstChild;
  NodeAnother := XmldocAnother.documentElement.firstChild.firstChild;

  while Assigned(NodeAnother) do
  begin
    NodeNext := NodeAnother.NextSibling;
    i := 0;
    while (i < NodeBase.childNodes.length)
        and (NodeBase.childNodes[i].firstChild.text
          <> NodeAnother.firstChild.text) do
      Inc(i);
    if i >= NodeBase.childNodes.length then
    begin
      NodeBase.appendChild(NodeAnother);
    //end else begin
    //  NodeBase.childNodes[i].childNodes.DeleteAllChilds;  <<<<<<<
    //  for i2 := 0 to NodeAnother.childNodes.length - 1 do
    //    NodeBase.childNodes[i].appendChild(NodeAnother.childNodes[0]);
    end;
    NodeAnother := NodeNext;
  end;

  XmldocBase.save(aTargetFile);
  Result := True;
end;
macht aus dem in Beitrag #3 dieses
XML-Code:
<?xml version="1.0"?>
<root>
  <nodes>
    <node>
      <Kenn>Kennung1</Kenn>   << müßte noch gelöscht werden
      <Wert>Wert1</Wert>      << müßte noch gelöscht werden
      <Kenn>Kennung1</Kenn>
      <Kenn>Kennung2</Kenn>
    </node>
    <node>
      <Kenn>Kennung2</Kenn>   << müßte noch gelöscht werden
      <Wert>Wert2</Wert>      << müßte noch gelöscht werden
      <Wert>Wert1</Wert>
      <Wert>Wert22222222</Wert>
    </node>
    <node>
      <Kenn>Kennung3</Kenn>
      <Wert>Wert3</Wert>
    </node>
    <node>
      <Kenn>Kennung4</Kenn>
      <Wert>Wert4</Wert>
    </node>
    <node>
      <Kenn>Kennung5</Kenn>
      <Wert>Wert5</Wert>
    </node>
  </nodes>
</root>

padavan 23. Sep 2009 15:44

Re: (unbekannte) XML Dateien zusammenführen bzw. mergen
 
Vielen Dank himitsu,

das Ergebnis ist nah dran.
Da scheint noch ein kleiner Schleifenfehler inne zu wohnen.

Das kommentierte Ergebnis müsste lauten:

Delphi-Quellcode:
<root>
  <nodes>
    <node>
      <Kenn>Kennung1</Kenn>   << müßte noch gelöscht werden << Das stimmt doch
      <Wert>Wert1</Wert>      << müßte noch gelöscht werden << Das stimmt doch
      <Kenn>Kennung1</Kenn>                                  << Das ist zuviel
      <Kenn>Kennung2</Kenn>                                  << Das ist zuviel
    </node>
    <node>
      <Kenn>Kennung2</Kenn>   << müßte noch gelöscht werden << Das stimmt doch
      <Wert>Wert2</Wert>      << müßte noch gelöscht werden
      <Wert>Wert1</Wert>                                     << Das ist zuviel
      <Wert>Wert22222222</Wert>                              << richtig!!!
    </node>
    <node>
      <Kenn>Kennung3</Kenn>
      <Wert>Wert3</Wert>
    </node>
    <node>
      <Kenn>Kennung4</Kenn>
      <Wert>Wert4</Wert>
    </node>
    <node>
      <Kenn>Kennung5</Kenn>
      <Wert>Wert5</Wert>
    </node>
  </nodes>
</root>




Zitat:

Wie um Himmels Willen, wie löscht man bei diesem Ding die alten Nodes?
ich nehme an mit
Delphi-Quellcode:
      NodeBase.childNodes[i].removeChild(???)
Nur einen sinnvollen Parameter hab ich noch nicht gefunden. Delphi schimpft immer das der zu entfernende Knoten ein Untergeordneter Knoten sein müsse.

himitsu 23. Sep 2009 15:54

Re: (unbekannte) XML Dateien zusammenführen bzw. mergen
 
OK, wenn dem so ist, dann laß mal hierbei
Delphi-Quellcode:
if i >= NodeBase.childNodes.length then
begin
  NodeBase.appendChild(NodeAnother);
end else begin
  NodeBase.childNodes[i].childNodes.DeleteAllChilds;  <<<<<<<
  for i := 0 to NodeAnother.childNodes.length - 1 do
    NodeBase.childNodes[i].appendChild(NodeAnother.childNodes[0]);
end;
den Else-Zweig weg ... ich glaub dann stimmts

[edit]
warte mal, ich glaub da stimmt was mit den Indize nicht

[edit2]
OK, da in der For.Schleife stimmte der Index nicht FOR i2 und nicht FOR i :oops: ,
aber egal, das würde ja nun eh verschwinden ... hab's oben im Post #7 mal editiert

padavan 23. Sep 2009 16:13

Re: (unbekannte) XML Dateien zusammenführen bzw. mergen
 
ach das mit I2 wollte ich auch gerade schreiben.

Aber, den elsezweig ausklammern ist nicht richtig, genau der macht das richtige. Du hast schon recht, es fehlt nur noch das löschen der vorhandenen alten childnodes.

Das Ergebnis Deiner korrigierten Routine ist jetzt

Delphi-Quellcode:
<root>
   <nodes>
      <node>
         <Kenn>Kennung1</Kenn> << raus, dann stimmts
         <Wert>Wert1</Wert>    << raus, dann stimmts
         <Kenn>Kennung1</Kenn>
         <Wert>Wert1</Wert>
      </node>
      <node>
         <Kenn>Kennung2</Kenn> << raus, dann stimmts
         <Wert>Wert2</Wert>    << raus, dann stimmts
         <Kenn>Kennung2</Kenn>
         <Wert>Wert22222222</Wert>
      </node>
      <node>
         <Kenn>Kennung3</Kenn>
         <Wert>Wert3</Wert>
      </node>
      <node>
         <Kenn>Kennung4</Kenn>
         <Wert>Wert4</Wert>
      </node>
      <node>
         <Kenn>Kennung5</Kenn>
         <Wert>Wert5</Wert>
      </node>
   </nodes>
</root>
Fehlt also nur noch das Löschen, dann sollte es stimmen.

mit Pfusch
Delphi-Quellcode:
  while Assigned(NodeAnother) do
  begin
    NodeNext := NodeAnother.NextSibling;
    i := 0;
    while (i < NodeBase.childNodes.length)
        and (NodeBase.childNodes[i].firstChild.text
          <> NodeAnother.firstChild.text) do
      Inc(i);
    if i >= NodeBase.childNodes.length then
    begin
      NodeBase.appendChild(NodeAnother);
    end else begin
//      NodeBase.childNodes[i].childNodes.DeleteAllChilds;  <<<<<<<
      NodeBase.childNodes[i].removeChild(NodeBase.childNodes[i].firstChild);
      NodeBase.childNodes[i].removeChild(NodeBase.childNodes[i].firstChild);


      for i2 := 0 to NodeAnother.childNodes.length - 1 do
        NodeBase.childNodes[i].appendChild(NodeAnother.childNodes[0]);
    end;
    NodeAnother := NodeNext;
  end;
edit: hier stimmt doch was nicht, da i2 gar nicht in der Schleife vorkommt...

Kommt das richtige Ergebnis:
Delphi-Quellcode:
<root>
   <nodes>
      <node>
         <Kenn>Kennung1</Kenn>
         <Wert>Wert1</Wert>
      </node>
      <node>
         <Kenn>Kennung2</Kenn>
         <Wert>Wert22222222</Wert>
      </node>
      <node>
         <Kenn>Kennung3</Kenn>
         <Wert>Wert3</Wert>
      </node>
      <node>
         <Kenn>Kennung4</Kenn>
         <Wert>Wert4</Wert>
      </node>
      <node>
         <Kenn>Kennung5</Kenn>
         <Wert>Wert5</Wert>
      </node>
   </nodes>
</root>


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:34 Uhr.
Seite 1 von 3  1 23      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz