Funcion XML reparada y mejoradaEl comentario de uno de los usuarios, @Fran, me ha echo revisar la función xml2array() y he visto que en una primera versión al hacerla destinada directamente a la extracción de datos del servidor REST de riya, el array generado no trataba bien los datos multidimensionales con mismo campo hermano, así­ que me he puesto un rato y la he reescrito para extraer todos los datos de una forma mas coherente y de paso darle mas funcionalidad. La función actual tiene 2 modos de funcionamiento. El modo de funcionamiento depende del tipo de datos que se le introduzca de manera que si se introduce un string que contenga la dirección de un archivo en la salida del archivo se dará como resultado un array que contendrá la estructura completa del XML. Si en cambio lo que se introduce es un array procedente de la anterior modalidad generará el contenido XML para posteriormente poder guardarlo.

Como todo esto se ve mejor en ejemplos os dejo un par.
Dentro del primer tipo de uso de la función podemos configurárala en 3 tipos de salida a partir del 2º valor de la función.

      light: Da como resultado un array con los datos valor entre tags y atributos dentro de las tag.

      PHP:
      1. $datos = xml("ejemplo.xml", "light");
      2. print_r($datos);

      full: Da como resultado un array multidimensional que contiene todos los datos internos y externos de la función.

      PHP:
      1. $datos = xml("ejemplo.xml", "full");
      2. print_r($datos);

      clean: Da como resultado un array con los datos completos del XML (nombre del tag, valores, numero de linea, indicadores de child...).

      PHP:
      1. $datos = xml("ejemplo.xml", "clean");
      2. print_r($datos);

Para utilizar la 2º parte de la función se necesita un array como el producido anteriormente. Una vez obtenido el array se introduce en el 1º valor de la función xml() y dará como resultado el texto en formato XML.

PHP:
  1. $xml = xml($datos);
  2. print_r($xml);

Para que podáis realizar las pruebas y usarla cuando queráis os dejo la función completa:

PHP:
  1. function xml($datos, $mode = ""){
  2.     if($mode == "REESCRITuRA"){#limpiado de los array
  3.         $valor = $datos;
  4.         if(!(is_array($valor) || is_object($valor))){ //si no es un objeto ni un array
  5.             $dato = $valor; //lo deja
  6.         } else { //si es un objeto
  7.             foreach($valor as $key => $valor1){ //lo conteo
  8.                 if(is_int($key)){
  9.                     $dato[]  = xml($valor1, "REESCRITuRA"); //
  10.                 } else {
  11.                     $dato[$key] = xml($valor1, "REESCRITuRA"); //
  12.                 }
  13.             }
  14.         }
  15.         return $dato;
  16.     } else {
  17.         if(!is_array($datos)){#xml2array
  18.             $simple = @file_get_contents($datos);
  19.             $simple = str_replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "<?xml version=\"1.0\" encoding=\"UTF-8\"?><data>", $simple);
  20.             $simple .= "</data>";
  21.             $p = xml_parser_create();
  22.             xml_parse_into_struct($p, $simple, $vals, $index);
  23.             xml_parser_free($p);
  24.             //ordenado de las variables
  25.             #cambio las key originales por su posicion en linea
  26.             foreach($index as $key => $valor){ //leo las key de los padres de linea
  27.                 foreach($index[$key] as $key_1 => $valor_1){ //leo los numeros de linea
  28.                     $out[$valor_1] = $vals[$valor_1]; //creo un array con los numeros de linea como keys para el ordenado
  29.                 }
  30.             }
  31.             #ordeno el array segun salio del arhcivo fuente XML
  32.             ksort($out); //ordeno los resultados como salieron del archivo XML fuente
  33.            
  34.             #declaro las variables contenedoras de la salida
  35.             $_out = $local = array();
  36.             $num = 0;
  37.             #leo el array del fuente
  38.             foreach($out as $key => $valor){
  39.                 #por cada open agrego un registro tag a local
  40.                 if($valor["type"] == "open"){
  41.                     $local[] = "[".$valor["tag"]."]"."[".$num."]";
  42.                 }
  43.                 #por cada close busco la ultima aparicion del tag q se cierra y lo elimino
  44.                 if($valor["type"] == "close"){
  45.                     array_pop($local);
  46.                 }
  47.                
  48.                 #si no se abre ni se cierra, recorro el array con los local y lo imprimo en forma de ruta/array
  49.                 if($valor["type"] == "complete"){
  50.                     $_datos   = "$"."_out";
  51.                     $__datos        = "$"."__out";//
  52.                     foreach($local as $ruta){
  53.                         $_datos  .=  $ruta;
  54.                         $__datos    .=  $ruta;//
  55.                     }
  56.                     #al terminar el conteo del local construyo el cargador de la ruta del array de salida y lo ejecuto.
  57.                     $_datos   .= "[".$valor["tag"]."] = array(\"value\" => $"."valor[\"value\"], \"attributes\" => $"."valor[\"attributes\"]);";
  58.                     $__datos        .= "[".$valor["tag"]."] = $"."valor;";//
  59.                     eval($_datos);
  60.                     eval($__datos);//
  61.                 } else {
  62.                     if($valor["type"] == "close"){
  63.                         $num++;
  64.                     }
  65.                 }
  66.             }
  67.             //fin ordenado de las variables
  68.             if($mode == "light" || $mode == ""){//limpio de arrays multiples
  69.                 return xml($_out["DATA"][0], "REESCRITuRA");
  70.             }
  71.             if($mode == "full"){//todos los array generados
  72.                 return array("full" => xml($__out["DATA"][0], "REESCRITuRA"), "clean" => xml($_out["DATA"][0], "REESCRITuRA"), "values" => $vals, "lines" => $index, "original" => $simple);
  73.             }
  74.             if($mode == "clean"){//pasado por el sistema de ordenado de archivos
  75.                 return xml($__out["DATA"][0], "REESCRITuRA");
  76.             }
  77.         } else {#array2xml
  78.             $array = $datos;
  79.             $f = $mode;
  80.             #declaro el encabezado de declaración del XML
  81.             if($f != "INITIaTE"){
  82.                 $out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
  83.             }
  84.             #recorro el array actual obteniendo todos los tag si contiene mas arrays
  85.             foreach($array as $key => $value){ //recorro los tags repetidos
  86.                 if(array_key_exists("value", $value)){
  87.                     $out_atrib = "";
  88.                     if(count($value["attributes"])>0){
  89.                         foreach($value["attributes"] as $atrib_name => $atrib){
  90.                             $out_atrib .= " ".$atrib_name."=\"".$atrib."\"";
  91.                         }
  92.                     }
  93.                     $out .= "<".$key.$out_atrib.">".$value["value"]."</".$key.">\n";
  94.                 } else {
  95.                     foreach($value as $_key => $id){ //recorro los contenidos de cada uno de los tag
  96.                         $out .= "<".$key.">\n";
  97.                         $out .= xml($id, "INITIaTE");
  98.                         $out .= "</".$key.">\n";
  99.                     }
  100.                 }
  101.             }
  102.             return $out;
  103.         }
  104.     }
  105. }

El archivo utilizado para el testado de la función ha sido ejemplo.xml situado en la misma carpeta del servidor que el archivo que contení­a xml().
El contenido de ejemplo.xml era:

XML:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <padre>
  3.   <hijo>
  4.     <nombre apellido="gonzalez">paquito</nombre>
  5.     <cumpleanios>1/11/1980</cumpleanios>
  6.     <sexo>hombre</sexo>
  7.     <edad></edad>
  8.   </hijo>
  9.   <hijo>
  10.     <nombre apellido="zuarezz" segundo_apellido="marquez">juanito</nombre>
  11.     <cumpleanios>1/08/1983</cumpleanios>
  12.     <sexo>hombre</sexo>
  13.     <sexo>si, hombre </sexo>
  14.     <residencia>
  15.         <calle>c/</calle>
  16.         <num>c/</num>
  17.     </residencia>
  18.     <residencia>
  19.         <calle>c/</calle>
  20.         <num>c/</num>
  21.     </residencia>
  22.   </hijo>
  23.   <hija>
  24.     <nombre apellido="gonzalez">pepita</nombre>
  25.     <cumpleanios>1/08/1983</cumpleanios>
  26.     <sexo>mujerr</sexo>
  27.   </hija>
  28. </padre>
  29.  
  30. <padre>
  31.   <tio>
  32.     <nombre apellido="gonzalez">paquito</nombre>
  33.     <cumpleanios>1/11/1980</cumpleanios>
  34.     <sexo>hombre</sexo>
  35.     <edad></edad>
  36.   </tio>
  37.   <sobrino>
  38.     <nombre apellido="zuarezz">juanito</nombre>
  39.     <cumpleanios>1/08/1983</cumpleanios>
  40.     <sexo>hombre</sexo>
  41.     <sexo>que si, es un hombre </sexo>
  42.     <residencia>
  43.         <calle>c/</calle>
  44.         <num>c/</num>
  45.     </residencia>
  46.     <residencia>
  47.         <calle>c/</calle>
  48.         <num>c/</num>
  49.     </residencia>
  50.   </sobrino>
  51.   <hija>
  52.     <nombre apellido="gonzalez">pepa</nombre>
  53.     <cumpleanios>1/08/1983</cumpleanios>
  54.     <sexo>mujer</sexo>
  55.   </hija>
  56. </padre>

Que lo disfrutéis.

Actualización: Nueva version de esta Función. Version de XML() 2.5