Velocidad eficiencia al analizar XML con XMLStarlet en zsh o bash.
Tenemos una aplicación zsh bastante compleja que utiliza archivos XML para almacenar su configuración y datos. El enfoque actual para leer y escribir en esos archivos es utilizando xmlstarlet.
Cuando actualizamos un archivo, redirigimos el archivo XML completo varias veces, una vez por cada atributo o elemento que modificamos, de la siguiente manera:
cat "$config" \
| xml_addSubnode "/a/b/c" "foo" \
| xml_createOrUpdateAttribute "/a/b/c/foo[last()]" "attr1" "zzzz" \
| xml_createOrUpdateAttribute "/a/b/c/foo[last()]" "attr2" "wwww" \
| xml_addSubnode "/a/b/c/foo[last()]" "attr3" \
| xml_createOrUpdateAttribute "/a/b/c/foo[last()]/bar" "attr4" "zzzz" \
| xml_createOrUpdateAttribute "/a/b/c/foo[last()]/bar" "attr5" "kkkk" \
| xml_update "$config"
Los atributos se leen en variables de shell llamando a la función xml
cada vez de forma separada:
local foo="$(xml_value "$xpath" "$config")"
local bar="$(xml_value "$xpath" "$config")"
...
Las funciones de utilidad se reducen a lo siguiente:
xml_addSubnode() {
...
cat | xml ed -s "$elementXPath" -t elem -n "$element"
}
xml_createOrUpdateAttribute()
{
...
cat | xml ed --update ... --insert ...
}
xml_value()
{
...
xml sel -t -v "$xPath" "$xmlFile"
}
xml_update()
{
...
cat > "$file"
}
Este código funciona correctamente, pero obviamente el rendimiento es horrible.
¿Cómo se puede mejorar la eficiencia de este código? ¿Qué otras formas hay de analizar XML con zsh o bash que permitan una ejecución más rápida?
Usar otro formato también es una opción, aunque requeriría cierto esfuerzo de migración. Conozco el analizador JSON jq
, pero el modo de uso sería similar a xmlstarlet
y no ganaría mucho si sigo el mismo enfoque, ¿verdad?
El programa se ejecuta en FreeBSD.
davy.ai
Maneras de hacer el análisis de XML en zsh eficiente
El enfoque actual de lectura y escritura de archivos XML utilizando
xmlstarlet
funciona de manera funcional, pero el rendimiento es horrible. Una forma más eficiente de hacer esto sería utilizandoxmlint
, que es otra herramienta de procesamiento de XML en línea de comandos que se puede utilizar para realizar varias operaciones de XML, incluyendo análisis, validación, consultas XPath y transformaciones XSL.Las funciones de utilidad como
xml_addSubnode()
,xml_createOrUpdateAttribute()
yxml_value()
podrían optimizarse minimizando la cantidad de tuberías de salida. En lugar de enviar la salida cada vez, sería más eficiente modificar el archivo XML en memoria y actualizarlo una vez. Esto se puede hacer pasando el archivo como el último argumento axml ed
en lugar de utilizar tuberías.Además, en lugar de llamar a
xml
cada vez de forma separada para leer los valores de los atributos, podemos extraer todos los valores a la vez utilizandoxml sel
y almacenarlos en un arreglo asociativo. Esto se puede hacer utilizando la opción-N ns=http://www.example.com/` para establecer un espacio de nombres y utilizando la opción
-m` para hacer coincidir todos los elementos de interés.Otra opción para analizar XML con
zsh
obash
sería utilizar un lenguaje de script como Python o Perl, que tienen potentes bibliotecas de análisis de XML. Sin embargo, esto requeriría más esfuerzo en términos de reescribir el código en otro lenguaje.Otra opción sería migrar a otro formato como JSON utilizando
jq
, pero como se mencionó anteriormente, esto requeriría un esfuerzo de migración y es posible que no se obtengan mejoras significativas en el rendimiento si seguimos el mismo enfoque.Dado que el programa se ejecuta en FreeBSD, también podríamos explorar el uso de otras herramientas de procesamiento de XML como
libxml2
, que es una biblioteca C que proporciona un conjunto de funciones de análisis y procesamiento de XML.En general, para mejorar la eficiencia del análisis de XML en
zsh
, debemos minimizar la cantidad de tuberías de salida, extraer todos los valores de atributos a la vez y explorar otras herramientas de procesamiento de XML comoxmlint
ylibxml2
.