2012-04-15 18 views
17

Tengo 2 archivos 1.xml y 2.xml, ambos con una estructura similar y me gustaría tener uno. Intenté muchas soluciones, pero solo tuve errores: francamente, no tengo idea de cómo funcionaron esos guiones.Fusionar archivos XML en PHP

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> 

me gustaría crear un nuevo archivo merged.xml con la siguiente estructura

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

¿Cómo debo hacer eso? ¿Puedes explicarme la manera de hacerlo? ¿Cómo puedo hacerlo con más archivos? Gracias

Editar

Lo he intentado?

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

Siguiendo el consejo Torious miré en el manual DOMDocument y se encontró un ejemplo:

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

pero crea archivos XML mal:

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

Y yo no puede usar este archivo correctamente Necesito la estructura correcta y aquí tengo el tipo de pegar un archivo en otro. Me gustaría "pegar" solo las etiquetas de todos los elementos. ¿Qué debería cambiar?

Edit3

aquí es una respuesta - sobre la base de la respuesta Torious - simplemente adaptado a mis necesidades - // comprobar editado

$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 
+0

Trate de usar el DOM, iniciar [aquí] (http://www.php.net/manual/en/domdocument.loadxml.php). Tenga en cuenta que si desea fusionar documentos XML (de diferentes fuentes 'DOMDocument', tendrá que usar' importNode' (más o menos) en algún momento. – Torious

Respuesta

17

Dado que usted ha puesto en un esfuerzo, he codificado algo que debería funcionar

Tenga en cuenta que esto es un código no probado, pero se entiende.

Depende de usted para que se convierta en funciones bonitas. Asegúrate de entender lo que está pasando; poder trabajar con DOM probablemente te ayudará en muchos escenarios futuros. Lo mejor de la norma DOM es que tienes prácticamente las mismas operaciones en muchos lenguajes/plataformas de programación diferentes.

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

    } 
+0

+1 para hacer aburridas traducciones – worenga

+0

gracias por la solución - Tuve que cambiar algunas cosas - compruebe edit3 sección // edit - significa que cambié una línea – andrewpo

+0

se me olvidó gracias de nuevo – andrewpo

-2

¿Qué tal:

<?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>'); 
0

creo que la forma más simple está cambiando XML a la matriz primero, combinar dos matriz que son mucho más fácil y sencillo. Finalmente cambie la matriz a xml. Puede ser útil para la situación en la que desee combinar dos archivos XML directamente. Solo necesita considerar qué tecla es la posición en la que desea agregar los nodos secundarios.

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

Uso: Crear un 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);