En primer lugar tengo que admitir que me encantan los estándares informáticos. Si todos siguieran los estándares de la industria, Internet sería un medio mejor. El uso de formatos estandarizados de intercambio de datos hace viables modelos informáticos abiertos e independientes de la plataforma. Por eso soy un entusiasta de XML.
Afortunadamente, mi lenguaje de programación favorito no sólo soporta XML sino que lo soporta cada vez más. PHP me permite publicar rápidamente documentos XML en Internet, recopilar información estadística sobre documentos XML y convertir documentos XML a otros formatos. Por ejemplo, suelo utilizar las capacidades de procesamiento XML de PHP para gestionar artículos y libros que escribo en XML.
En este artículo, discutiré cualquier uso del analizador Expat integrado de PHP para procesar documentos XML. A través de ejemplos, demostraré el método de procesamiento de Expat. Al mismo tiempo, el ejemplo puede mostrarle cómo:
Crear su propia función de procesamiento
Conversión de documentos XML en sus propias estructuras de datos PHP
Introducción
El analizador de Expat XML, también llamado procesador XML, permite a los programas acceder a la estructura y el contenido de los documentos XML. Expat es un analizador XML para el lenguaje de programación PHP. También se utiliza en otros proyectos, como Mozilla, Apache y Perl.
¿Qué es un analizador basado en eventos?
Hay dos tipos básicos de analizadores XML:
Analizadores basados en árboles: convierten documentos XML en estructuras de árbol. Este tipo de analizador analiza el artículo completo y proporciona una API para acceder a cada elemento del árbol resultante. Su estándar común es DOM (Document Object Model).
Analizador basado en eventos: trate los documentos XML como una serie de eventos. Cuando ocurre un evento especial, el analizador llamará a la función proporcionada por el desarrollador para manejarlo.
El analizador basado en eventos tiene una vista centrada en los datos del documento XML, lo que significa que se centra en la parte de datos del documento XML en lugar de en su estructura. Estos analizadores procesan el documento de principio a fin e informan eventos como (inicio de elemento, fin de elemento, inicio de datos de características, etc.) a la aplicación a través de funciones de devolución de llamada. El siguiente es un documento XML de ejemplo para "Hola-Mundo":
<saludo>
Hola Mundo
</greeting>
El analizador basado en eventos informará como tres eventos:
elemento de inicio: saludo
El comienzo del elemento CDATA, el valor es: Hola mundo
Elemento final: saludo
A diferencia de los analizadores basados en árboles, los analizadores basados en eventos no producen una estructura que describa el documento. En los elementos CDATA, el analizador basado en eventos no le permitirá obtener la información de saludo del elemento principal.
Sin embargo, proporciona un acceso de nivel inferior, lo que permite una mejor utilización de los recursos y un acceso más rápido. De esta manera, no es necesario guardar todo el documento en la memoria; de hecho, todo el documento puede incluso tener un tamaño mayor que el valor real de la memoria;
Expat es un analizador basado en eventos. Por supuesto, si usa Expat, también puede generar una estructura de árbol nativa completa en PHP si es necesario.
El ejemplo anterior de Hello-World incluye el formato XML completo. Pero no es válido porque no hay una DTD (Definición de tipo de documento) asociada ni una DTD incrustada.
Para Expat, esto no supone ninguna diferencia: Expat es un analizador que no comprueba la validez y, por tanto, ignora cualquier DTD asociado al documento. Sin embargo, debe tenerse en cuenta que el documento aún debe estar completamente formateado; de lo contrario, Expat (al igual que otros analizadores compatibles con XML) se detendrá y mostrará un mensaje de error.
Como analizador que no comprueba la validez, la velocidad y el peso ligero de Exapt lo hacen muy adecuado para aplicaciones de Internet.
Compilación de Expat Expat
se puede compilar en la versión PHP3.0.6 (o superior). A partir de Apache 1.3.9, Expat se ha incluido como parte de Apache. En sistemas Unix, puedes compilarlo en PHP configurando PHP con la opción -with-xml.
Si compila PHP como un módulo de Apache, Expat se incluirá como parte de Apache de forma predeterminada. En Windows, debe cargar la biblioteca de vínculos dinámicos XML.
Ejemplos XML: XMLstats
Una forma de aprender sobre las funciones de Expat es a través de ejemplos. El ejemplo que vamos a analizar es el uso de Expat para recopilar estadísticas sobre documentos XML.
Para cada elemento del documento, se generará la siguiente información:
el número de veces que se utiliza el elemento en el documento
La cantidad de datos de caracteres en este elemento.
el elemento padre del elemento
elementos secundarios del elemento
Nota: Para fines de demostración, usamos PHP para generar una estructura para guardar el elemento principal y el elemento secundario del elemento.
preparada
para generar la instancia del analizador XML es xml_parser_create(). Esta instancia se utilizará para todas las funciones futuras. Esta idea es muy similar a la etiqueta de conexión de la función MySQL en PHP. Antes de analizar el documento, los analizadores basados en eventos generalmente requieren que usted registre una función de devolución de llamada, que se llamará cuando ocurra un evento específico. Expat no tiene eventos de excepción. Define los siguientes siete eventos posibles:
objeto Descripción de la función de análisis XML
elemento xml_set_element_handler()
datos de caracteres iniciales y finales del elemento xml_set_character_data_handler() datos de inicio de caracteres
entidad externa xml_set_external_entity_ref_handler() entidad externa Entidad externa no analizada
xml_set_unparsed_entity_decl_handler (. ) La aparición de una
instrucción de procesamiento de entidad externa no resuelta xml_set_processing_instruction_handler() La aparición de una
declaración de notación de instrucción de procesamiento xml_set_notation_decl_handler() La aparición de una declaración de notación
predeterminada xml_set_default_handler() Otros eventos sin una función de controlador especificada
Todas las funciones de devolución de llamada deben usar una instancia de analizador como su primer parámetro (hay otros parámetros además).
Para ver el script de muestra al final de este artículo. Lo que debe tener en cuenta es que utiliza funciones de procesamiento de elementos y funciones de procesamiento de datos de caracteres. La función del controlador de devolución de llamada del elemento se registra a través de xml_set_element_handler().
Esta función toma tres parámetros:
una instancia del analizador
El nombre de la función de devolución de llamada que maneja el elemento inicial.
El nombre de la función de devolución de llamada que maneja el elemento de cierre.
La función de devolución de llamada debe existir cuando comienza el análisis del documento XML. Deben definirse de manera consistente con los prototipos descritos en el manual de PHP.
Por ejemplo, Expat pasa tres argumentos a la función controladora para el elemento inicial. En el ejemplo del script, se define de la siguiente manera:
función start_element($parser, $name, $attrs)
El primer parámetro es el identificador del analizador, el segundo parámetro es el nombre del elemento inicial y el tercer parámetro contiene todos los atributos y valores de la matriz de elementos.
Una vez que comience a analizar el documento XML, Expat llamará a su función start_element() y pasará los parámetros cada vez que encuentre el elemento inicial.
La opción Plegado de casos de XML
utiliza la función xml_parser_set_option () para desactivar la opción de plegado de casos. Esta opción está activada de forma predeterminada, lo que hace que los nombres de los elementos pasados a las funciones del controlador se conviertan automáticamente a mayúsculas. Pero XML distingue entre mayúsculas y minúsculas (por lo que las mayúsculas y minúsculas son muy importantes para los documentos XML estadísticos). Para nuestro ejemplo, la opción de plegado de estuche debe estar desactivada.
Analizando el documento
Después de completar todos los preparativos, ahora el script finalmente puede analizar el documento XML:
Xml_parse_from_file(), una función personalizada, abre el archivo especificado en el parámetro y lo analiza en un tamaño de 4kb.
xml_parse(), al igual que xml_parse_from_file(), devolverá falso cuando se produzca un error, es decir, cuando el documento XML no esté completamente formateado.
Puede utilizar la función xml_get_error_code() para obtener el código numérico del último error. Pase este código numérico a la función xml_error_string() para obtener la información del texto del error.
Genera el número de línea actual de XML, lo que facilita la depuración.
Durante el proceso de análisis, se llama a la función de devolución de llamada.
Describir la estructura del documento
Al analizar un documento, la pregunta que debe abordarse con Expat es: ¿cómo mantener una descripción básica de la estructura del documento?
Como se mencionó anteriormente, el analizador basado en eventos en sí no produce ninguna información estructural.
Sin embargo, la estructura de etiquetas es una característica importante de XML. Por ejemplo, la secuencia de elementos <libro><título> significa algo diferente a <figura><título>. Dicho esto, cualquier autor le dirá que los títulos de libros y los títulos de imágenes no tienen nada que ver entre sí, aunque ambos utilicen el término "título". Por lo tanto, para procesar XML de manera eficiente con un analizador basado en eventos, debe usar sus propias pilas o listas para mantener la información estructural sobre el documento.
Para reflejar la estructura del documento, el script necesita conocer al menos el elemento principal del elemento actual. Esto no es posible con la API de Exapt. Solo informa eventos del elemento actual sin ninguna información contextual. Por lo tanto, necesita crear su propia estructura de pila.
El ejemplo de script utiliza una estructura de pila primero en entrar, último en salir (FILO). A través de una matriz, la pila guardará todos los elementos iniciales. Para la función de procesamiento del elemento inicial, la función array_push() empujará el elemento actual a la parte superior de la pila. En consecuencia, la función de procesamiento del elemento final elimina el elemento superior mediante array_pop().
Para la secuencia <libro><título></título></libro>, la pila se completa de la siguiente manera:
elemento inicial libro: asigne "libro" al primer elemento de la pila ($pila[0]).
Título del elemento inicial: Asigne "título" a la parte superior de la pila ($stack[1]).
Título del elemento final: elimina el elemento superior de la pila ($stack[1]).
Título del elemento final: elimina el elemento superior de la pila ($stack[0]).
PHP3.0 implementa el ejemplo controlando manualmente el anidamiento de elementos a través de una variable $profundidad. Esto hace que el guión parezca más complejo. PHP4.0 utiliza las funciones array_pop() y array_push() para hacer que el script parezca más conciso.
Recopilación de datos
Para recopilar información sobre cada elemento, el script necesita recordar los eventos de cada elemento. Guarde todos los diferentes elementos del documento utilizando una variable de matriz global $elementos. Los elementos de la matriz son instancias de la clase de elemento y tienen 4 propiedades (variables de la clase)
$count: la cantidad de veces que se encontró el elemento en el documento
$chars: número de bytes de eventos de caracteres en el elemento
$padres - elemento padre
$childs - elementos secundarios
Como puede ver, guardar instancias de clases en una matriz es pan comido.
Nota: Una característica de PHP es que puede recorrer toda la estructura de clases a través de un bucle while(list() = each()), tal como recorre toda la matriz correspondiente. Todas las variables de clase (y nombres de métodos cuando usa PHP3.0) se generan como cadenas.
Cuando se encuentra un elemento, debemos incrementar su contador correspondiente para realizar un seguimiento de cuántas veces aparece en el documento. El elemento de recuento en el elemento $elements correspondiente también se incrementa en uno.
También debemos informarle al elemento padre que el elemento actual es su elemento hijo. Por lo tanto, el nombre del elemento actual se agregará al elemento en la matriz $childs del elemento principal. Finalmente, el elemento actual debería recordar quién es su padre. Por lo tanto, el elemento principal se agrega al elemento en la matriz $parents del elemento actual.
Mostrar estadísticas
El código restante recorre la matriz $elements y sus submatrices para mostrar sus estadísticas. Este es el bucle anidado más simple. Aunque genera los resultados correctos, el código no es conciso ni tiene habilidades especiales. Es solo un bucle que puede usar todos los días para completar su trabajo.
Los ejemplos de script están diseñados para ser invocados desde la línea de comandos mediante el enfoque CGI de PHP. Por lo tanto, el formato de salida de los resultados estadísticos es el formato de texto. Si desea utilizar el script en Internet, debe modificar la función de salida para generar el formato HTML.
Resumen
Exapt es un analizador XML para PHP. Como analizador basado en eventos, no produce una descripción estructural del documento. Pero al proporcionar acceso de bajo nivel, esto permite una mejor utilización de los recursos y un acceso más rápido.
Como analizador que no verifica la validez, Expat ignora las DTD adjuntas a los documentos XML, pero se detendrá con un mensaje de error si el documento no está bien formado.
Proporcionar controladores de eventos para procesar documentos.
Cree sus propias estructuras de eventos, como pilas y árboles, para aprovechar el marcado de información estructurada XML.
Todos los días aparecen nuevos programas XML y el soporte de PHP para XML se fortalece constantemente (por ejemplo, se agregó soporte para el analizador XML basado en DOM LibXML).
Con PHP y Expat, puede prepararse para los próximos estándares que serán válidos, abiertos e independientes de la plataforma.
Ejemplo
<?
/*************************************************** ***** *******************************
* Nombre: Ejemplo de análisis XML: estadísticas de información de documentos XML
* describir
* Este ejemplo utiliza el analizador Expat de PHP para recopilar y contar información del documento XML (por ejemplo: el número de apariciones de cada elemento, elementos principales y elementos secundarios).
* Archivo XML como parámetro./xmlstats_PHP4.php3 test.xml
* $Requires: Requisitos para expatriados: Expat PHP4.0 está compilado en modo CGI
************************************************** * **************************/
// El primer parámetro es el archivo XML
$archivo = $argv[1]
// Inicialización de variables
$elementos = $pila = matriz();
$total_elements = $total_chars = 0;
//Clase básica de elementos
elemento de clase
{
var $cuenta = 0;
var $caracteres = 0;
var $padres = matriz();
var $niños = matriz();
}
// Función para analizar archivos XML
función xml_parse_from_file($parser, $archivo)
{
si(!file_exists($archivo))
{
die("No se puede encontrar el archivo "$archivo".");
}
si(!($fp = @fopen($archivo, "r")))
{
die("No se puede abrir el archivo "$file".");
}
mientras($datos = fread($fp, 4096))
{
if(!xml_parse($parser, $datos, feof($fp)))
{
retorno (falso);
}
}
fclose($fp);
retorno(verdadero);
}
// Función de resultado de salida (forma de cuadro)
función print_box($título, $valor)
{
printf("n+%'-60s+n", "");
printf("|%20s", "$título:");
printf("%14s", $valor);
printf("%26s|n", "");
printf("+%'-60s+n", "");
}
// Función de resultado de salida (forma de línea)
función print_line($título, $valor)
{
printf("%20s", "$título:");
printf("%15sn", $valor);
}
// Función de clasificación
función my_sort($a, $b)
{
return(is_object($a) && is_object($b)? $b->count - $a->count: 0);
}
función start_element($parser, $nombre, $atributos)
{
global $elementos, $stack;
// ¿El elemento ya está en la matriz global $elementos?
if(!isset($elementos[$nombre]))
{
// No - agrega una instancia de clase de un elemento
$elemento = nuevo elemento;
$elementos[$nombre] = $elemento;
}
// Incrementa el contador de este elemento en uno
$elementos[$nombre]->count++;
// ¿Hay un elemento padre?
si(isset($pila[count($pila)-1]))
{
// Sí - asigna el elemento padre a $last_element
$last_element = $stack[count($stack)-1]
// Si la matriz del elemento principal del elemento actual está vacía, inicialícela a 0
if(!isset($elementos[$nombre]->padres[$último_elemento]))
{
$elementos[$nombre]->padres[$last_element] = 0;
}
// Incrementa el contador del elemento padre de este elemento en uno
$elements[$name]->parents[$last_element]++;
// Si la matriz de elementos secundarios del elemento principal del elemento actual está vacía, se inicializa a 0
if(!isset($elements[$last_element]-> niños[$ nombre]))
{
$elementos[$último_elemento]->hijos[$nombre] = 0;
}
// Agrega uno al contador de elementos secundarios del elemento principal del elemento.
$elementos[$último_elemento]->hijos[$nombre]++;
}
//Agrega el elemento actual a la pila
array_push($pila, $nombre);
}
función stop_element($parser, $nombre)
{
global $stack;
// Elimina el elemento superior de la pila
array_pop($pila);
}
función char_data ($ analizador, $ datos)
{
global $elementos, $stack, $profundidad
// Aumenta el número de caracteres del elemento actual;
$elementos[$pila][count($pila)-1]]->chars += strlen(trim($datos));
}
// Generar instancia del analizador
$parser = xml_parser_create();
// Establecer la función de procesamiento
xml_set_element_handler($parser, "start_element", "stop_element");
xml_set_character_data_handler($parser, "char_data");
// Analizar el archivo
);
$ret = xml_parse_from_file($parser, $archivo);
si(!$ret)
{
die(sprintf("Error XML: %s en la línea %d",
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser)));
}
// Liberar el analizador
xml_parser_free($parser);
// Libera el elemento auxiliar
unset($elementos["current_element"]);
unset($elements["last_element"]);
// Ordenar según el número de elementos
uasort($elementos, "my_sort");
// Recorre $elementos para recopilar información del elemento.
while(lista($nombre, $elemento) = cada uno($elementos))
{
print_box("Nombre del elemento", $nombre);
print_line("Recuento de elementos", $elemento->recuento);
print_line("Recuento de caracteres", $elemento->chars);
printf("n%20sn", "* Elementos principales"
// Recorre el elemento principal y genera el resultado).
while(lista($clave, $valor) = cada uno($elemento->padres))
{
print_line($clave, $valor);
}
si(cuenta($elemento->padres) == 0)
{
printf("%35sn", "[elemento raíz]");
}
// Recorre el elemento secundario de este elemento y genera el resultado.
printf("n%20sn", "*Elementos secundarios");
while(lista($clave, $valor) = cada uno($elemento->hijos))
{
print_line($clave, $valor);
}
si(cuenta($elemento->hijos) == 0)
{
printf("%35sn", "[sin hijos]");
}
$total_elementos += $elemento->recuento;
$total_chars += $elemento->caracteres;
}
// resultado final
print_box("Total de elementos", $total_elementos);
print_box("Total de caracteres", $total_chars);
?>