Объединение XML-файлов в PHP

У меня есть 2 файла 1.xml и 2.xml имеющие сходную структуру, и я хотел бы иметь их. Я пробовал много решений, но у меня были только ошибки – честно говоря, я понятия не имею, как эти скрипты работали.

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> 

Я хотел бы создать новый файл merged.xml со следующей структурой

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

Как мне это сделать? Можете ли вы объяснить мне, как это сделать? Как я могу сделать это с большим количеством файлов? благодаря

редактировать

Что я пробовал?

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

Следуя советам Torious, я просмотрел руководство DOMDocument и нашел пример:

 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') 

Но он создает неправильный файл xml:

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

И я не могу использовать этот файл правильно. Мне нужна правильная структура, и здесь у меня есть вид вставки одного файла в другой. Я хотел бы «вставить» теги не только для всех элементов. Что я должен изменить?

EDIT3

вот ответ, основанный на Torious ответе – просто адаптировал его к моим потребностям – проверьте // отредактированный

 $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 

Поскольку вы прилагаете усилия, я закодировал что-то, что должно работать.

Обратите внимание, что это непроверенный код, но вы получаете идею.

Это зависит от вас, чтобы превратить его в красивые функции. Убедитесь, что вы понимаете, что происходит; возможность работать с DOM, вероятно, поможет вам во многих будущих сценариях. Замечательная вещь о стандарте DOM заключается в том, что у вас практически одинаковые операции на разных языках программирования / платформах.

  $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); } 

Я думаю, что самый простой способ – сначала сменить XML на массив, объединить два массива, которые намного проще и понятнее. Наконец, измените массив на xml. Это может помочь в ситуации, когда вы хотите напрямую объединить два файла XML. Вам нужно только рассмотреть, какой ключ – это позиция, в которую вы хотите добавить дочерние узлы.

 function xml_to_array($sxi){ $a = array(); for( $sxi->rewind(); $sxi->valid(); $sxi->next() ) { if(!array_key_exists($sxi->key(), $a)){ $a[$sxi->key()] = array(); } if($sxi->hasChildren()){ $a[$sxi->key()] = $this->xml_to_array($sxi->current()); } else{ $a[$sxi->key()] = strval($sxi->current()); } } return $a; } function array_to_xml( $data, &$xml_data ) { foreach( $data as $key => $value ) { if( is_numeric($key) ){ $key = 'item'.$key; //dealing with <0/>..<n/> issues } if( is_array($value) ) { $subnode = $xml_data->addChild($key); array_to_xml($value, $subnode); } else { $xml_data->addChild("$key",htmlspecialchars("$value")); } } } 

Использование: создать SimpleXMLIterator

 $xml1 = new \SimpleXMLIterator('test1.xml',null,true); $a = xml_to_array($xml1); //convert xml to array $xml2 = new \SimpleXMLIterator('test2.xml',null,true); $b = xml_to_array($xml2); $c = new SimpleXMLElement('<?xml version="1.0"?><data></data>'); $a['new_node']=$b; array_to_xml($a,$c); var_dump($c); 

Как насчет :

 <?php // Read file 1 $xmlfilecontent = file_get_contents('xml1.xml'); // Concat file 2 $xmlfilecontent .= file_get_contents('xml2.xml'); // remove <items> tags preg_replace('/<items[^"]*">/','',$xmlfilecontent); // remove </items> tags $xmlfilecontent = str_replace('</items>','',$xmlfilecontent ); // remove <res> tags $xmlfilecontent = str_replace('<res>','',$xmlfilecontent ); // remove </res> tags $xmlfilecontent = str_replace('</res>','',$xmlfilecontent ); // load XML Object - also add res and items + amount $xmlobj = simple_xml_load_string('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'.PHP_EOL.'<res>'.PHP_EOL.'<items total="'.substr_count( $xmlfilecontent , '<item>').'">'.PHP_EOL.$xmlfilecontent.PHP_EOL.'</items>'.PHP_EOL.'</res>');