Gostaria de saber como posso obter o valor de um nó com os seguintes caminhos:
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
do seguinte 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>
Também quero atribuir esse valor à variável para uso posterior. Deixe-me saber sua ideia.
Comentários
- Nunca use o bash para analisar árvores estruturadas de dados arbitrários. Use um analisador XML real. Eu recomendo XMLStarlet .
- stackoverflow.com/questions/893585/how-to -parse-xml-in-bash
Resposta
Usando bash
e xmllint
(conforme fornecido pelas 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
Caso haja apenas uma string XML e o uso de um arquivo temporário seja evitado, os descritores de arquivo são a melhor opção com xmllint
(que é fornecido /dev/fd/3
como um argumento de arquivo aqui):
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
Comentários
- Página de manual: xmlsoft.org/xmllint.html
Resposta
Embora já existam muitas respostas, eu “tocarei 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
Com um pouco de mágica, você pode até mesmo defini-las como variáveis diretamente:
Resposta
Usando xmllint e a opção –xpath , é muito fácil. Você pode simplesmente fazer isso:
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
Se você precisa obter o atributo de um elemento, também é fácil usar XPath. Imagine que você tenha o arquivo:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <addon name="Turn Off" version="0.10.0" provider-name="Dag Wieërs"> ..snip.. </addon>
As instruções shell necessárias seriam:
VERSION=$(xmllint --xpath "string(/addon/@version)" $ADDON_XML) AUTHOR=$(xmllint --xpath "string(/addon/@provider-name)" $ADDON_XML)
Resposta
O seguinte funciona quando executado em seus dados de teste:
{ 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)
Isso coloca o conteúdo em variáveis host
, username
, password
e dbname
.
Comentários
- xmlstarlet: comando não encontrado, então este comando não é útil para mim: (
- @MagePsycho
bash
não tem nenhum suporte integrado para análise XML. Você também precisa ter uma ferramenta que tenha (xmlstarlet, xsltproc, um Python moderno, etc) , ou você pode ‘ t analisar XML corretamente. - @CharlesDuffy há uma maneira de obter o valor usando o padrão regex ou então?
- @MagePsycho você pode apenas instalar o xmlstarlet. Em qualquer caso, você deve nunca usar regul expressões ar para analisar (X) HTML .
- @MagePsycho Eu estava prestes a postar o mesmo link que o terdon já fez. Resumindo: Não.
Resposta
Um puro bash
função, apenas para o caso infeliz quando você não tem permissão para instalar nada apropriado. Isso pode, e provavelmente falhará, em um XML mais 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 conhecidos:
- lento
- pesquisas apenas por nomes de tag
- nenhuma decodificação de entidade de caractere
Resposta
Este comentário usa apenas comandos e métodos sh / bash! /test.xml é o seu arquivo do tipo XML na primeira pergunta …
#!/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
saída:
host: localhost username: root password: pass123 dbname: testdb
se você quiser gravar esses valores no arquivo, 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 irá sobrescrever seus arquivos locais usados apenas para obter valores (seus dados será perdido dos arquivos de saída)
Resposta
Você pode usar a codificação da interface de linha de comando php em scripts bash para lidar com diversos scripts que realmente se estendem por várias linhas de codificação. Primeiro, tente fazer sua solução usando scripts PHP e depois passe os parâmetros usando o modo CLI. Assim, você pode obter controle sobre os excelentes usos dos analisadores XML.
O ambiente parece que você pode usar o PHP no modo cliente por meio do acesso ssh / shell.
php -f yourxmlparser.php
Agora, faça todas as coisas dentro do seu arquivo php. Use os parâmetros de linha de comando que ele pode usar.
Você pode até atribuir esses valores de retorno ao ambiente Shell para continuar o restante de seus scripts de shell.
E a outra maneira é usar | opção grep para corresponder ao valor necessário dentro do arquivo xml, se você tiver certeza da estrutura do arquivo xml que não muda com o tempo.