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
- Nunca uses bash para analizar árboles estructurados de datos arbitrarios. Utilice un analizador XML real. Recomiendo XMLStarlet .
- stackoverflow.com/questions/893585/how-to -parse-xml-in-bash
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
- Página de manual: xmlsoft.org/xmllint.html
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.