Wednesday, May 26, 2010

merge two XML by PHP; Replace Nodes

Merging two XML files is just painful, especially if you have complex files. Here is the best way and most efficient way that I have found after researching a lot. It is still complected by I think it would be great. imagine you got two XML files as below:

(?php
$xml1 = (((XML
(?xml version="1.0"?)
(family)
(parent)
(child1)child 1(/child1)
(child2)child 1.1(/child2)
(/parent)
(/family)
XML;
?)

(?php
$xml2 = (((XML
(?xml version="1.0"?)
(family)
(parent)
(child1)child 1(/child1)
(child2)child 2.1(/child2)
(/parent)
(/family)
XML;
?)

You want to merge them together, but the most complicated part is, your manager ask you to replace the node value of child2 with node value of child1; on the other hand, do not change the node name... So, the only thing that you should do is copy and paste the following code and it 100% works!!!! :D

(?php
loadXML($xml1);
$xpathT1 = new DOMXpath($xliffT1);
$nodeListT1 = $xpathT1->query('/family/parent/child2');

$xliffT2 = new DomDocument;
$xliffT2->loadXML($xml2);

$xpathT2 = new DOMXpath($xliffT2);
$nodeListT2 = $xpathT2->query('/family/parent/child1');
$nodeListTargetT2 = $xpathT2->query('/family/parent/child2');

mergeXliffFiles($xliffT1, $nodeListT1, $xliffT2, $nodeListT2, $nodeListTargetT2);


function mergeXliffFiles($xliffT1, $nodeListT1, $xliffT2, $nodeListT2, $nodeListTargetT2){

for($i=0; $i< $nodeListT2->length; $i++){
$xliffT1Node = $xliffT1->createElement('Child1', $nodeListT1->item($i)->nodeValue);
$xliffT1->appendChild($xliffT1Node);
$xliffT1Node->setAttribute('xml:lang','fr-FR');
$newnode = $xliffT2->importNode($xliffT1->getElementsByTagName('Child1')->item($i), true);
$oldnode = $nodeListT2->item($i);
$oldnode->parentNode->replaceChild($newnode, $oldnode);

$xliffT2Node = $xliffT2->createElement('Child2', $nodeListTargetT2->item($i)->nodeValue);
$xliffT2->appendChild($xliffT2Node);
$xliffT2Node->setAttribute('xml:lang','fr-FR');
$newnode2 = $xliffT2->importNode($xliffT2->getElementsByTagName('Child1')->item($i), true);
$oldnode2 = $nodeListTargetT2->item($i);
$oldnode2->parentNode->replaceChild($xliffT2Node, $oldnode2);
}

$xpathNew = new DOMXpath($xliffT2);
$nodelistNew = $xpathNew->query('/family/parent');

$j = 0;
foreach($nodelistNew as $node){
$source[0] = $xliffT2->getElementsByTagName('Child1')->item(0);
$asb = $xliffT2->createElement('child1', $source[0]->nodeValue);
$source[0]->parentNode->replaceChild($asb, $source[0]);

$target[0] = $xliffT2->getElementsByTagName('Child2')->item(0);
$asb = $xliffT2->createElement('child2', $target[0]->nodeValue);
$target[0]->parentNode->replaceChild($asb, $target[0]);
$j++;

}

$xliffT2->save('test2.xml');
}
?>

What you are gonna have on test2.xml is something like that:

(family)
(parent)
(child1)child 1.1(/child1)
(child2)child 2.1(/child2)
(/parent)
(/family)