Como analisar XML usando shellscript?

Gostaria de saber qual seria a melhor maneira de analisar um arquivo XML usando shellscript?

  • Alguém deveria fazer isso manualmente?
  • Existe biblioteca de terceiros?

Se você já fez isso, se você poderia me dizer como você conseguiu fazer isso?

Você poderia tentar xmllint

O programa xmllint analisa um ou mais arquivos XML, especificados na linha de comando como xmlfile. Imprime vários tipos de saída, dependendo das opções selecionadas. É útil para detectar erros no código XML e no analisador de XML itse

Ele permite selecionar elementos no documento XML por xpath, usando a opção –pattern.

No Mac OS X (Yosemite), ele é instalado por padrão.
No Ubuntu, se ainda não estiver instalado, você pode executar o apt-get install libxml2-utils

Aqui está um exemplo completo de trabalho.
Se estiver apenas extraindo endereços de e-mail, você poderia simplesmente fazer algo como:
1) Suponha que o arquivo XML spam.xml é como

    The Pope pope@vatican.gob.va 0   George Bush father@nwo.com 1   George Bush Jr son@nwo.com 0    

2) Você pode obter os e-mails e processá-los com este pequeno código bash:

 #!/bin/bash emails=($(grep -oP '(?<=email>)[^<]+' "/my_path/spam.xml")) for i in ${!emails[*]} do echo "$i" "${emails[$i]}" # instead of echo use the values to send emails, etc done 

O resultado deste exemplo é:

 0 pope@vatican.gob.va 1 father@nwo.com 2 son@nwo.com 

Nota importante:
Não use isso para assuntos sérios. Está tudo bem para brincar, obter resultados rápidos, aprender grep, etc., mas você definitivamente deve procurar, aprender e usar um analisador XML para produção (veja o comentário de Micha abaixo).

Há também o xmlstarlet (que também está disponível para o Windows).

http://xmlstar.sourceforge.net/doc/xmlstarlet.txt

Estou surpreso que ninguém tenha mencionado o xmlsh . A declaração da missão:

Um shell de linha de comando para XML Baseado na filosofia e no design dos Shells Unix

O xmlsh fornece um ambiente de script familiar, mas especificamente adaptado para scripts de processos xml.

Uma lista de comandos semelhantes a shell é fornecida aqui .

Eu uso muito o comando xed que é equivalente a sed para XML, e permite pesquisa baseada em XPath e substitui.

Tente sgrep . Não está claro exatamente o que você está tentando fazer, mas eu certamente não tentaria escrever um analisador XML no bash.

Você tem o xml_grep instalado? É um padrão de utilitário baseado em perl em algumas distribuições (veio pré-instalado no meu sistema CentOS). Em vez de dar uma expressão regular, você dá uma expressão xpath.

Um projeto novo é o pacote xml-coreutils com xml-cat, xml-cp, xml-cut, xml-grep, …

http://xml-coreutils.sourceforge.net/contents.html

Tente usar o xpath. Você pode usá-lo para analisar elementos de uma tree xml.

http://www.ibm.com/developerworks/xml/library/x-tipclp/index.html

Isso realmente está além dos resources do script de shell. O shell script e as ferramentas padrão do Unix estão bem em analisar os arquivos orientados a linha, mas as coisas mudam quando você fala sobre XML. Mesmo tags simples podem apresentar um problema:

 Data  Data  Data Data  

Imagine tentar escrever um script de shell que possa ler os dados contidos nele. Os três exemplos muito simples de XML mostram diferentes maneiras pelas quais isso pode ser um problema. Os dois primeiros exemplos são exatamente a mesma syntax em XML. O terceiro simplesmente tem um atributo ligado a ele. O quarto contém os dados em outra tag. Comandos simples sed , awk e grep não conseguem capturar todas as possibilidades.

Você precisa usar uma linguagem de script completa como Perl, Python ou Ruby. Cada um deles tem módulos que podem analisar dados XML e tornar a estrutura subjacente mais fácil de acessar. Eu usei XML :: Simple em Perl. Levei algumas tentativas para entendê-lo, mas ele fez o que eu precisava, e facilitou muito a minha programação.

Aqui está uma function que irá converter pares e atributos de valor de nome XML em variables ​​bash.

http://www.humbug.in/2010/parse-simple-xml-files-using-bash-extract-name-value-pairs-and-attributes/

Aqui está uma solução usando o xml_grep (porque o xpath não fazia parte do nosso distributable e eu não queria adicioná-lo a todas as máquinas de produção) …

Se você estiver procurando por uma configuração específica em um arquivo XML, e se todos os elementos em um determinado nível de tree forem exclusivos e não houver atributos, você poderá usar esta function útil:

 # File to be parsed xmlFile="xxxxxxx" # use xml_grep to find settings in an XML file # Input ($1): path to setting function getXmlSetting() { # Filter out the element name for parsing local element=`echo $1 | sed 's/^.*\///'` # Verify the element is not empty local check=${element:?getXmlSetting invalid input: $1} # Parse out the CDATA from the XML element # 1) Find the element (xml_grep) # 2) Remove newlines (tr -d \n) # 3) Extract CDATA by looking for *element> CDATA /dev/null | tr -d '\n' | sed -n -e "s/.*$element>[[:space:]]*\([^[:space:]].*[^[:space:]]\)[[:space:]]*<\/$element.*/\1/p"` # Return the result echo $getXmlSettingResult } #EXAMPLE logPath=`getXmlSetting //config/logs/path` check=${logPath:?"XML file missing //config/logs/path"} 

Isso funcionará com essa estrutura:

   /path/to/logs   

Ele também funcionará com isso (mas não manterá as novas linhas):

    /path/to/logs    

Se você tiver duplicado ou ou , ele retornará apenas o último. Você provavelmente pode modificar a function para retornar uma matriz se encontrar várias correspondências.

FYI: Este código funciona no RedHat 6.3 com o GNU BASH 4.1.2, mas eu não acho que estou fazendo algo específico para isso, então deve funcionar em qualquer lugar.

OBSERVAÇÃO: Para qualquer pessoa nova no script, certifique-se de usar os tipos corretos de aspas, todas as três são usadas neste código (aspas simples normais = literal, aspas simples invertidas = executar e aspas duplas = grupo).