XML() versión 3.0, lee y escribe archivos de XML a Array y de Array a XML fácilmente
Hoy toca otra actualización de una función relativamente antigua.
El XML es un lenguaje de almacenamiento de datos principalmente que hoy en día se usa para casi todo, desde las API online, RSS o los principales sistemas de comunicación entre empresas o gobiernos hasta las mas simples galerías de imágenes flash o conversaciones de MSN Messenger utilizan este sistema para encapsular los datos de manera fácil para las maquinas y los humanos. Por esto es un sistema que no podemos dejar de lado en nuestras aplicaciones. Por esto me dispongo a sacar la tercera versión de la función xml().
Esta nueva actualización duplica la velocidad de la anterior ya que ha sido reescrita entera y el único error detectado es que no respeta los saltos de linea dentro de los valores de los archivos XML, algo que por el momento no he podido solucionar. Está optimizada para funcionar con archivos UTF-8 y como en las anteriores versiones es capaz de autodetectar si el dato introducido es una dirección de archivo (local o de la red), un string de datos XML o un array de datos XML.
En el caso de ser un texto XML o una dirección a un archivo la función dará como resultado un array con todo el archivo XML. Si por el contrario lo introducido es un array, dará como resultado el mismo en formato XML.
Para conseguir un resultado optimo en la conversión "array2xml" el array tiene que tener un formato especifico. Si el formato no es el correcto se producirá una perdida de datos en la conversión del mismo. Para evitar esto se recomienda realizar test comparativos entre los resultados.
La actualización a la versión 3.0 como se indica mas arriba solo tiene un parámetro de entrada. El resto de parámetros de la función son de uso interno para realizar las lecturas recursivas del array en la conversión a XML.
Aquí van unos cuantos ejemplos.
Ejemplo de conversion de archivo local a array, (se necesita tener un archivo con contenido XML que tenga como nombre sample.xml en el mismo directorio):
-
$xml = xml('sample.xml');
Ejemplo de verificación simple del XML anterior (de xml a array y de ese mismo array a xml):
-
$xml = xml('sample.xml');
-
$xml = xml($xml);
Ejemplo de array a XML (se necesita tener un array xml almacenado en la variable $array):
-
$xml = xml($array);
-
echo $xml;
Ejemplos de conversión de archivo remoto XML en array:
-
$file = 'http://www.w3schools.com/XML/note.xml';
-
$xml = xml($file);
-
$file = 'http://www.w3schools.com/XML/cd_catalog.xml';
-
$xml = xml($file);
-
$file = 'http://www.w3schools.com/XML/plant_catalog.xml';
-
$xml = xml($file);
-
$file = 'http://www.w3schools.com/XML/simple.xml';
-
$xml = xml($file);
y aquí os dejo el la función. Como podéis leer la parte de conversión de datos de XML a Array es una variación del código de Binny V. A. de xml2array() por lo que el error de los saltos de linea seguirán estando hasta que lo corrija o le meta mas mano yo.
-
function xml($datos='', $key='', $sangria = 0){
-
if($sangria == 0 ) $s[] = '<?xml version="1.0" encoding="ISO-8859-1"?'.'>';
-
$array = $datos;
-
foreach($array as $k => $v){
-
$_value = $v['value'];
-
$_attr = $v['attr'];
-
-
$_s = "\n";
-
foreach($_attr as $namevar => $valuevar){ $_s .= $_sangria.' '.$namevar.'="'.$valuevar.'"'."\n"; }
-
$_s .= $_sangria;
-
}
-
$s[] = $_sangria.'<'.$__keys.$_s.'>';
-
$s[] = $_sangria.'</'.$__keys.'>'; //
-
} else {
-
if( ($v_key==false) ){
-
$s[] = $_sangria.'<'.$__keys.$_s.'>';
-
$s[] = xml($v, $__keys, $sangria+1);
-
$s[] = $_sangria.'</'.$__keys.'>'; //
-
} else {
-
$s[] = xml($v, $__keys, $sangria);
-
}
-
}
-
} else {
-
$s[] = $_value!='' ? $_sangria.'<'.$__keys.$_s.'>'.$_value.'</'.$__keys.'>' : $_sangria.'<'.$__keys.$_s.' />';
-
}
-
}
-
$contents = $datos;
-
$get_attributes = 1;
-
if(!function_exists('xml_parser_create')) { return array( 'error' => array('value' => 'funcion \')xml_parser_create()\' no encotrada!' ) ); } //si la funcion no existe
-
-
//Correccion de &
-
-
//Correccion de \n
-
-
//Obtencion de los datos XML
-
#xml_parser_set_option( $parser, XML_OPTION_SKIP_WHITE, 1 );
-
#xml_parser_set_option( $parser, XML_OPTION_TARGET_ENCODING, 'UTF-8' );
-
-
-
//Iniciamos los valores
-
-
$current = &$xml_array;
-
-
// Go through the tags.
-
foreach($xml_values as $data) {
-
-
$result = '';
-
if($get_attributes) {//The second argument of the function decides this.
-
-
//Set the attributes too.
-
foreach($attributes as $attr => $val) {
-
if($get_attributes == 1) $result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
-
/** :TODO: should we change the key name to '_attr'? Someone may use the tagname 'attr'. Same goes for 'value' too */
-
}
-
}
-
$result = $value;
-
}
-
-
// Ordenado del array // // // // // //
-
-
//See tag status and do the needed.
-
if($type == "open") {//The starting of the tag '<tag>'
-
$parent[$level-1] = &$current;
-
-
$current[$tag] = $result;
-
$current = &$current[$tag];
-
} else { //There was another element with the same tag name
-
} else {
-
}
-
$current = &$current[$tag][$last];
-
}
-
-
} elseif($type == "complete") { //Tags that ends in 1 line '<tag />'
-
//See if the key is already taken.
-
$current[$tag] = $result;
-
} else { //If taken, put all things inside a list(array)
-
} else { //If it is not an array...
-
$current[$tag] = array($current[$tag],$result); //...Make it an array using using the existing value and the new value
-
}
-
}
-
-
} elseif($type == 'close') { $current = &$parent[$level-1]; }//End of tag '</tag>'
-
}
-
return($xml_array);
-
} else {
-
}
-
}
Que lo disfrutéis!
Actualización: Para quitar el error de los saltos de linea solo hay que comentar la linea 58 (xml_parser_set_option( $parser, XML_OPTION_SKIP_WHITE, 1 ); por #xml_parser_set_option( $parser, XML_OPTION_SKIP_WHITE, 1 );)
A petición del publico añado un nuevo ejemplo que ilustre mas "claramente" como usar la función.. usare el 1º ejemplo de lectura de xml externo de este articulo.
-
$file = 'http://www.w3schools.com/XML/note.xml';
-
$xml = xml($file);
-
-
//muesta los valores de las ramas con un salto de linea al fina
-
-
//hace lo mismo que antes pero usando $note para referirnos a la rama 'NOTE'
-
$note = $xml['NOTE'];
-
-
//forma para recorrer una sola rama de forma automática
-
//en este caso mostrando las ramas parientes y sus valores en una frase
-
//(se podría recorrer el array desde el principio en vez de desde NOTE, pero
-
// al tener un solo valor es innecesario hacer dos veces el foreach)
-
foreach($xml['NOTE'] as $key => $valor){
-
}
Para mas aclaraciones... comentarios
Creo que este còdigo me puede ser muy pràctico, pero me gustaria que alguien me explicara como puedo acceder a cada uno de los datos del largo array resultante, una vez leido el archivo xml!!
Hola Hecturt, pues es algo bastante sencillo.. simplemente accedes como si fuera un array normal, escribiendo la variable y entre corchetes la rama a la que quieres acceder..
Si necesitas ver todas las ramas de una variable o las ramas que tienes a partir de un punto lo mas practico es que hagas un print_r para ir guiando…
Si necesitas mas información con ejemplos de variables puedes usar la web oficial de PHP.
PD. No te pierdas tampoco foreach(), otra de las funciones mas practicas para recorrer las ramas automáticamente e ir usando sus valores.
Gracias antares, pero….
Yo ya habia utilizado alguna función parecida en alguna web y accedia a los datos una sintaxis como esta:
igualando la funcion a $db:
echo $db[$i]->titol (siendo $i la posición en el array)
Sin embargo, con tu funcion no lo consigo de ningun modo!
ah! vale… ahora te comprendí mejor Hecturt.. cuando pones -> es para llamar a un dato en un objeto… eso pasa cuando usas una clase… a mi me parecen las clases algo engorrosas con php y por eso procuro usar en mis funciones siempre arrays.
Para acceder a un dato de un array tienes que poner $valor['clave1']['clave2']……..
en tu ejemplo en el que todo el árbol del xml esta metido dentro de $db y la rama a la que quieres acceder es
$itendrías que ponerecho $db[$i];sin más.. pero recuerda que echo solo se usa para strings si lo que contiene$db[$i]es un array hay tendrías que especificarle mas la rama o hacerprint_r($db[$i]);Te agradeceria un ejemplo práctico para acabar de entender la cuestión.
Tomando tu xml de ejemplo, como puedo imprimir en pantalla el dato “pepita gonzalez”?
Gracias por la paciencia
Hola Hecturt, te he dejado un ejemplo extendido al final del articulo usando como base un archivo xml de la w3cSchool.
El código tiene 3 ejemplos que leen los valores del xml como te comentaba antes..
Si necesitas alguna ayuda mas solo coméntamelo y q no se te olvide que me puedes “invitar a un cafe” desde la parte izquierda del articulo
Hola antares500!!!!
Estoy jugando con la rutina y ha surgido un problema con CDATA…. Resulta que usando un xml con CDATA llega un momento que el parser devuelve en la variable $type el valor “cdata” y este valor no está contemplado… solamente open, complete y close.
Visto esto… podría echarme un cable?????
Gracias.
Hola @Surferkurban, muchas gracias por el aviso pero creo que necesitaría un ejemplo del XML que te está fallando.. si puedes poner un enlace al xml seria una ayuda para poder reproducir tu error.. supongo que con un detector dentro de la función para que elimine esa rama padre seria suficiente así que seria cuestión de pruebas..
De todas formas para no complicarte si tienes instalada la librería puede que puedas utilizar xml_parse_into_struct() nativamente desde PHP.