Ik zou graag willen weten hoe ik de waarde van een knooppunt met de volgende paden kan krijgen:
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
uit de volgende 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>
Ook wil ik die waarde aan de variabele toewijzen voor verder gebruik. Laat me je idee weten.
Reacties
- Gebruik nooit bash om gestructureerde bomen van willekeurige gegevens te parseren. Gebruik een echte XML-parser. Ik raad XMLStarlet aan.
- stackoverflow.com/questions/893585/how-to -parse-xml-in-bash
Antwoord
Met bash
en xmllint
(zoals gegeven door de tags):
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
In het geval dat er slechts een XML-string is en het gebruik van een tijdelijk bestand moet worden vermeden, zijn bestandsdescriptors de juiste keuze met xmllint
(die hier /dev/fd/3
als bestandsargument wordt gegeven):
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
Reacties
- Man-pagina: xmlsoft.org/xmllint.html
Antwoord
Hoewel er al veel antwoorden zijn, “bel ik in met 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
Met een beetje magie kun je deze zelfs rechtstreeks als variabelen instellen:
Antwoord
Met xmllint en de –xpath optie, het is heel gemakkelijk. U kunt dit eenvoudig doen:
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
Als u naar het kenmerk van een element moet gaan, is dat ook gemakkelijk met XPath. Stel je voor dat je het bestand hebt:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <addon name="Turn Off" version="0.10.0" provider-name="Dag Wieërs"> ..snip.. </addon>
De benodigde shell-instructies zouden zijn:
VERSION=$(xmllint --xpath "string(/addon/@version)" $ADDON_XML) AUTHOR=$(xmllint --xpath "string(/addon/@provider-name)" $ADDON_XML)
Answer
Het volgende werkt als het wordt uitgevoerd tegen uw testgegevens:
{ 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)
Dit plaatst de inhoud in variabelen host
, username
, password
en dbname
.
Reacties
- xmlstarlet: commando niet gevonden, dus dit commando is niet nuttig voor mij: (
- @MagePsycho
bash
heeft geen ingebouwde ondersteuning voor XML-parsing. Je hebt ofwel een tool nodig die dat wel doet (xmlstarlet, xsltproc, een moderne Python, enz.) , of je kunt ‘ XML correct parseren. - @CharlesDuffy is er een manier om de waarde te krijgen door het gebruik van een regex-patroon of anders?
- @MagePsycho, je kunt gewoon xmlstarlet installeren. In elk geval mag je nooit regul gebruiken ar-expressies om (X) HTML te ontleden.
- @MagePsycho Ik stond op het punt dezelfde link te plaatsen die terdon al deed. In het kort: Nee.
Antwoord
Een pure bash
functie, alleen voor het ongelukkige geval dat u niets passend mag installeren. Dit kan en zal waarschijnlijk mislukken bij meer gecompliceerde XML:
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 }
Gebruik :
bash-4.1$ xmlpath "config/global/resources/default_setup/connection/host" < MagePsycho.xml localhost
Bekende problemen:
- langzaam
- zoekt alleen op tagnamen
- geen karakter-entiteit-decodering
Antwoord
Deze opmerking gebruikt alleen sh / bash-commandos en -methoden! /test.xml is uw XML-typebestand bij de eerste vraag …
#!/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
output:
host: localhost username: root password: pass123 dbname: testdb
als u deze waarden naar een bestand wilt schrijven, gebruik dan deze methode:
#!/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
deze methode overschrijft uw lokale bestanden die alleen worden gebruikt om waarden op te halen (uw gegevens zal verloren gaan uit outputbestanden)
Answer
Je kunt gebruik maken van php command line interface codering in bash scripts om verschillende complexe scripts die feitelijk meerdere coderegels beslaan. Probeer eerst uw oplossing te maken met behulp van PHP-scripts en geef de parameters later door in de CLI-modus. Zodoende kunt u controle krijgen over uitmuntend gebruik van XML-parsers.
De omgeving lijkt erop dat u PHP in client-modus kunt gebruiken via ssh / shell-toegang.
php -f yourxmlparser.php
Doe nu alle dingen in je php-bestand. Maak gebruik van opdrachtregelparameters die nodig zijn.
U kunt zelfs die retourwaarden toewijzen aan de Shell-omgeving om de rest van uw shell-scripts voort te zetten.
En de andere manier is om | grep-optie om uw vereiste waarde in het xml-bestand overeen te laten komen, als u vrij zeker bent van de structuur van uw xml-bestand die in de loop van de tijd niet verandert.