¿Analizar XML para obtener el valor del nodo en el script bash?

Me gustaría saber cómo puedo obtener el valor de un nodo con las siguientes rutas:

config/global/resources/default_setup/connection/host config/global/resources/default_setup/connection/username config/global/resources/default_setup/connection/password config/global/resources/default_setup/connection/dbname 

del siguiente XML:

<?xml version="1.0"?> <config> <global> <install> <date><![CDATA[Tue, 11 Dec 2012 12:31:25 +0000]]></date> </install> <crypt> <key><![CDATA[70e75d7969b900b696785f2f81ecb430]]></key> </crypt> <disable_local_modules>false</disable_local_modules> <resources> <db> <table_prefix><![CDATA[]]></table_prefix> </db> <default_setup> <connection> <host><![CDATA[localhost]]></host> <username><![CDATA[root]]></username> <password><![CDATA[pass123]]></password> <dbname><![CDATA[testdb]]></dbname> <initStatements><![CDATA[SET NAMES utf8]]></initStatements> <model><![CDATA[mysql4]]></model> <type><![CDATA[pdo_mysql]]></type> <pdoType><![CDATA[]]></pdoType> <active>1</active> </connection> </default_setup> </resources> <session_save><![CDATA[files]]></session_save> </global> <admin> <routers> <adminhtml> <args> <frontName><![CDATA[admin]]></frontName> </args> </adminhtml> </routers> </admin> </config> 

También quiero asignar ese valor a la variable para su uso posterior. Déjame saber tu idea.

Comentarios

Responder

Usando bash y xmllint (según lo indicado por las etiquetas):

xmllint --version # xmllint: using libxml version 20703 # Note: Newer versions of libxml / xmllint have a --xpath option which # makes it possible to use xpath expressions directly as arguments. # --xpath also enables precise output in contrast to the --shell & sed approaches below. #xmllint --help 2>&1 | grep -i "xpath" 

{ # the given XML is in file.xml host="$(echo "cat /config/global/resources/default_setup/connection/host/text()" | xmllint --nocdata --shell file.xml | sed "1d;$d")" username="$(echo "cat /config/global/resources/default_setup/connection/username/text()" | xmllint --nocdata --shell file.xml | sed "1d;$d")" password="$(echo "cat /config/global/resources/default_setup/connection/password/text()" | xmllint --nocdata --shell file.xml | sed "1d;$d")" dbname="$(echo "cat /config/global/resources/default_setup/connection/dbname/text()" | xmllint --nocdata --shell file.xml | sed "1d;$d")" printf "%s\n" "host: $host" "username: $username" "password: $password" "dbname: $dbname" } # output # host: localhost # username: root # password: pass123 # dbname: testdb 

En caso de que solo haya una cadena XML y se deba evitar el uso de un archivo temporal, los descriptores de archivo son el camino a seguir con xmllint (que se proporciona /dev/fd/3 como argumento de archivo aquí):

set +H { xmlstr="<?xml version="1.0"?> <config> <global> <install> <date><![CDATA[Tue, 11 Dec 2012 12:31:25 +0000]]></date> </install> <crypt> <key><![CDATA[70e75d7969b900b696785f2f81ecb430]]></key> </crypt> <disable_local_modules>false</disable_local_modules> <resources> <db> <table_prefix><![CDATA[]]></table_prefix> </db> <default_setup> <connection> <host><![CDATA[localhost]]></host> <username><![CDATA[root]]></username> <password><![CDATA[pass123]]></password> <dbname><![CDATA[testdb]]></dbname> <initStatements><![CDATA[SET NAMES utf8]]></initStatements> <model><![CDATA[mysql4]]></model> <type><![CDATA[pdo_mysql]]></type> <pdoType><![CDATA[]]></pdoType> <active>1</active> </connection> </default_setup> </resources> <session_save><![CDATA[files]]></session_save> </global> <admin> <routers> <adminhtml> <args> <frontName><![CDATA[admin]]></frontName> </args> </adminhtml> </routers> </admin> </config> " # exec issue #exec 3<&- 3<<<"$xmlstr" #exec 3<&- 3< <(printf "%s" "$xmlstr") exec 3<&- 3<<EOF $(printf "%s" "$xmlstr") EOF { read -r host; read -r username; read -r password; read -r dbname; } < <( echo "cat /config/global/resources/default_setup/connection/*[self::host or self::username or self::password or self::dbname]/text()" | xmllint --nocdata --shell /dev/fd/3 | sed -e "1d;$d" -e "/^ *--* *$/d" ) printf "%s\n" "host: $host" "username: $username" "password: $password" "dbname: $dbname" exec 3<&- } set -H # output # host: localhost # username: root # password: pass123 # dbname: testdb 

Comentarios

Respuesta

Aunque ya hay muchas respuestas, voy a intervenir con xml2.

$ xml2 < test.xml /config/global/install/date=Tue, 11 Dec 2012 12:31:25 +0000 /config/global/crypt/key=70e75d7969b900b696785f2f81ecb430 /config/global/disable_local_modules=false /config/global/resources/db/table_prefix /config/global/resources/default_setup/connection/host=localhost /config/global/resources/default_setup/connection/username=root /config/global/resources/default_setup/connection/password=pass123 /config/global/resources/default_setup/connection/dbname=testdb /config/global/resources/default_setup/connection/initStatements=SET NAMES utf8 /config/global/resources/default_setup/connection/model=mysql4 /config/global/resources/default_setup/connection/type=pdo_mysql /config/global/resources/default_setup/connection/pdoType /config/global/resources/default_setup/connection/active=1 /config/global/session_save=files /config/admin/routers/adminhtml/args/frontName=admin 

Con un poco de magia, incluso puede establecerlas como variables directamente:

Responder

Usando xmllint y la opción –xpath , es muy fácil. Simplemente puede hacer esto:

XML_FILE=/path/to/file.xml HOST=$(xmllint --xpath "string(/config/global/resources/default_setup/connection/host)" $XML_FILE USERNAME=$(xmllint --xpath "string(/config/global/resources/default_setup/connection/username)" $XML_FILE PASSWORD=$(xmllint --xpath "string(/config/global/resources/default_setup/connection/password)" $XML_FILE DBNAME=$(xmllint --xpath "string(/config/global/resources/default_setup/connection/dbname)" $XML_FILE 

Si necesita acceder al atributo de un elemento, también es fácil usar XPath. Imagina que tienes el archivo:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <addon name="Turn Off" version="0.10.0" provider-name="Dag Wieërs"> ..snip.. </addon> 

Las declaraciones de shell necesarias serían:

VERSION=$(xmllint --xpath "string(/addon/@version)" $ADDON_XML) AUTHOR=$(xmllint --xpath "string(/addon/@provider-name)" $ADDON_XML) 

Respuesta

Lo siguiente funciona cuando se ejecuta con sus datos de prueba:

{ read -r host; read -r username; read -r password; read -r dbname; } \ < <(xmlstarlet sel -t -m /config/global/resources/default_setup/connection \ -v ./host -n \ -v ./username -n \ -v ./password -n \ -v ./dbname -n) 

Esto coloca el contenido en las variables host, username, password y dbname.

Comentarios

  • xmlstarlet: comando no encontrado, así que este comando no me es útil: (
  • @MagePsycho bash no tiene ningún soporte integrado para el análisis de XML. Necesitas tener una herramienta que lo haga (xmlstarlet, xsltproc, un Python moderno, etc.) , o puede ‘ t analizar XML correctamente.
  • @CharlesDuffy, ¿hay alguna manera de obtener el valor utilizando el patrón de expresiones regulares o de lo contrario?
  • @MagePsycho, simplemente puede instalar xmlstarlet. En cualquier caso, nunca debe usar regul ar expresiones para analizar (X) HTML .
  • @MagePsycho Estaba a punto de publicar el mismo enlace que terdon ya hizo. En resumen: No.

Respuesta

Un bash puro función, solo en el desafortunado caso en el que no se le permite instalar nada apropiado. Esto puede fallar, y probablemente fallará en XML más complicado:

 function xmlpath() { local expr="${1//\// }" local path=() local chunk tag data while IFS="" read -r -d "<" chunk; do IFS=">" read -r tag data <<< "$chunk" case "$tag" in "?"*) ;; "!–-"*) ;; "![CDATA["*) data="${tag:8:${#tag}-10}" ;; ?*"/") ;; "/"?*) unset path[${#path[@]}-1] ;; ?*) path+=("$tag") ;; esac [[ "${path[@]}" == "$expr" ]] && echo "$data" done }  

Uso :

bash-4.1$ xmlpath "config/global/resources/default_setup/connection/host" < MagePsycho.xml localhost 

Problemas conocidos:

  • lento
  • busca solo por nombres de etiqueta
  • sin decodificación de entidades de caracteres

Respuesta

¡Este comentario usa solo comandos y métodos sh / bash! /test.xml es su archivo de tipo XML en la primera pregunta …

#!/bin/sh cat /test.xml | while read line;do [ "$(echo "$line" | grep "<host>")" ]&& echo "host: $(echo $line | cut -f3 -d"[" | cut -f1 -d"]")" [ "$(echo "$line" | grep "<username>")" ]&& echo "username: $(echo $line | cut -f3 -d"[" | cut -f1 -d"]")" [ "$(echo "$line" | grep "<password>")" ]&& echo "password: $(echo $line | cut -f3 -d"[" | cut -f1 -d"]")" [ "$(echo "$line" | grep "<dbname")" ]&& echo "dbname: $(echo $line | cut -f3 -d"[" | cut -f1 -d"]")" done 

salida:

host: localhost username: root password: pass123 dbname: testdb 

si desea escribir estos valores en el archivo, use este método:

#!/bin/sh cat /test.xml | while read line;do [ "$(echo "$line" | grep "<host>")" ]&& echo "$line" | cut -f3 -d"[" | cut -f1 -d"]" > /config/global/resources/default_setup/connection/host [ "$(echo "$line" | grep "<username>")" ]&& echo "$line" | cut -f3 -d"[" | cut -f1 -d"]" > /config/global/resources/default_setup/connection/username [ "$(echo "$line" | grep "<password>")" ]&& echo "$line" | cut -f3 -d"[" | cut -f1 -d"]" > /config/global/resources/default_setup/connection/password [ "$(echo "$line" | grep "<dbname")" ]&& echo "$line" | cut -f3 -d"[" | cut -f1 -d"]" > /config/global/resources/default_setup/connection/dbname done 

este método sobrescribirá sus archivos locales utilizados solo para obtener valores (sus datos se perderá de los archivos de salida)

Respuesta

Puede utilizar la codificación de la interfaz de línea de comando php en scripts bash para manejar varios scripts que en realidad abarcan varias líneas de codificación. Primero, intente hacer su solución usando scripts PHP, y luego pase los parámetros usando el modo CLI. Por lo tanto, puede obtener control sobre los excelentes usos de los analizadores XML.

El entorno parece que puede usar PHP en modo cliente a través del acceso ssh / shell.

php -f yourxmlparser.php 

Ahora, haga todas las cosas dentro de su archivo php. Haga uso de los parámetros de línea de comando que puede tomar.

Incluso puede asignar esos valores de retorno al entorno Shell para continuar con el resto de sus scripts de shell.

Y la otra forma es usar | grep para que coincida con el valor requerido dentro del archivo xml, si está bastante seguro de que la estructura de su archivo xml no cambia con el tiempo.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *