Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merge XML files in PHP

Tags:

I have 2 files 1.xml and 2.xml both having similar structure and I would like to have one. I tried many solutions but I had errors only - frankly speaking I have no idea how those scripts worked.

1.xml:

<res>     <items total="180">         <item>             <id>1</id>             <title>Title 1</title>             <author>Author 1</author>         </item>         ...     </items> </res>  

2.xml:

<res>     <items total="123">         <item>             <id>190</id>             <title>Title 190</title>             <author>Author 190</author>         </item>         ...     </items> </res>  

I would like to create a new file merged.xml with the following structure

<res>     <items total="303">         <item>             <id>1</id>             <title>Title 1</title>             <author>Author 1</author>         </item>         ...  //items from 1.xml         <item>             <id>190</id>             <title>Title 190</title>             <author>Author 190</author>         </item>         ... //items from 2.xml     </items> </res>  

How should I do that? Can you explain me the way to do it? How can I do it with more files? Thanks

Edit

What I tried?

<?php function mergeXML(&$base, $add) {     if ( $add->count() != 0 )     $new = $base->addChild($add->getName());     else         $new = $base->addChild($add->getName(), $add);     foreach ($add->attributes() as $a => $b)     {         $new->addAttribute($a, $b);     }     if ( $add->count() != 0 )     {        foreach ($add->children() as $child)         {             mergeXML($new, $child);         }     } } $xml = mergeXML(simplexml_load_file('1.xml'), simplexml_load_file('2.xml')); echo $xml->asXML(merged.xml); ?> 

EDIT2

Following Torious advice I looked into DOMDocument manual and found an example:

function joinXML($parent, $child, $tag = null) {     $DOMChild = new DOMDocument;     $DOMChild->load($child);     $node = $DOMChild->documentElement;      $DOMParent = new DOMDocument;     $DOMParent->formatOutput = true;     $DOMParent->load($parent);      $node = $DOMParent->importNode($node, true);      if ($tag !== null) {         $tag = $DOMParent->getElementsByTagName($tag)->item(0);         $tag->appendChild($node);     } else {         $DOMParent->documentElement->appendChild($node);     }      return $DOMParent->save('merged.xml'); }  joinXML('1.xml', '2.xml') 

But it creates wrong xml file:

<res>     <items total="180">         <item>             <id>1</id>             <title>Title 1</title>             <author>Author 1</author>         </item>         ...     </items>     <res>         <items total="123">             <item>                 <id>190</id>                 <title>Title 190</title>                 <author>Author 190</author>             </item>             ...         </items>     </res>  </res>   

And I cannot use this file properly. I need correct structure and here I have kind of pasting one file into another. I would like to "paste" only item's not all tags. What should I change?

EDIT3

here is an answer - based on Torious answer - just adapted it to my needs - check //edited

$doc1 = new DOMDocument(); $doc1->load('1.xml');  $doc2 = new DOMDocument(); $doc2->load('2.xml');  // get 'res' element of document 1 $res1 = $doc1->getElementsByTagName('items')->item(0); //edited res - items  // iterate over 'item' elements of document 2 $items2 = $doc2->getElementsByTagName('item'); for ($i = 0; $i < $items2->length; $i ++) {     $item2 = $items2->item($i);      // import/copy item from document 2 to document 1     $item1 = $doc1->importNode($item2, true);      // append imported item to document 1 'res' element     $res1->appendChild($item1);  } $doc1->save('merged.xml'); //edited -added saving into xml file 
like image 517
andrewpo Avatar asked Apr 15 '12 16:04

andrewpo


1 Answers

Since you've put an effort in, I've coded something that should work.

Note that this is untested code, but you get the idea.

It's up to you to make it into pretty functions. Make sure you understand what's going on; being able to work with the DOM will probably help you out in a lot of future scenarios. The cool thing about the DOM standard is that you have pretty much the same operations in many different programming languages/platforms.

    $doc1 = new DOMDocument();     $doc1->load('1.xml');      $doc2 = new DOMDocument();     $doc2->load('2.xml');      // get 'res' element of document 1     $res1 = $doc1->getElementsByTagName('res')->item(0);      // iterate over 'item' elements of document 2     $items2 = $doc2->getElementsByTagName('item');     for ($i = 0; $i < $items2->length; $i ++) {         $item2 = $items2->item($i);          // import/copy item from document 2 to document 1         $item1 = $doc1->importNode($item2, true);          // append imported item to document 1 'res' element         $res1->appendChild($item1);      } 
like image 185
Torious Avatar answered Oct 23 '22 12:10

Torious