Como imprimir bastante XML a partir da linha de comando?


528

Relacionado: Como posso imprimir JSON em shell script (unix)?

Existe um shell script (unix) para formatar XML em formato legível por humanos?

Basicamente, quero transformar o seguinte:

<root><foo a="b">lorem</foo><bar value="ipsum" /></root>

... em algo assim:

<root>
    <foo a="b">lorem</foo>
    <bar value="ipsum" />
</root>

1
Para ter xmllintdisponível nos sistemas Debian, você precisa instalar o pacote libxml2-utils( libxml2não fornece esta ferramenta, pelo menos não no Debian 5.0 "Lenny" e 6.0 "Squeeze").
twonkeys 20/09/2013

Respostas:


909

libxml2-utils

Este utilitário vem com libxml2-utils:

echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    xmllint --format -

Perl's XML::Twig

Este comando vem com XML :: Twig módulo, às vezes xml-twig-toolsempacota:

echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    xml_pp

xmlstarlet

Este comando vem com xmlstarlet:

echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    xmlstarlet format --indent-tab

tidy

Verifique o tidypacote:

echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    tidy -xml -i -

Pitão

O Python xml.dom.minidompode formatar XML (python2 e python3):

echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    python -c 'import sys;import xml.dom.minidom;s=sys.stdin.read();print(xml.dom.minidom.parseString(s).toprettyxml())'

saxon-lint

Você precisa de saxon-lint:

echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    saxon-lint --indent --xpath '/' -

saxon-HE

Você precisa de saxon-HE:

 echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    java -cp /usr/share/java/saxon/saxon9he.jar net.sf.saxon.Query \
    -s:- -qs:/ '!indent=yes'

Resposta rápida e boa. A primeira opção parece ser mais onipresente nas instalações modernas do * nix. Um ponto menor; mas pode ser chamado sem trabalhar com um arquivo intermediário? Ou seja echo '<xml .. />' | xmllint --some-read-from-stdn-option,?
svidgen

O pacote está libxml2-utilsno meu lindo ubuntu.
franzlorenzon

1
Observe que "cat data.xml | xmllint --format - | tee data.xml" não funciona. No meu sistema, às vezes funcionava para arquivos pequenos, mas sempre truncava arquivos enormes. Se você realmente deseja fazer alguma coisa no local, leia backreference.org/2011/01/29/in-place-editing-of-files
user1346466

1
Para resolver UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 805: ordinal not in range(128)na versão python, você deseja definir PYTHONIOENCODING="UTF-8":cat some.xml | PYTHONIOENCODING="UTF-8" python -c 'import sys;import xml.dom.minidom;s=sys.stdin.read();print xml.dom.minidom.parseString(s).toprettyxml()' > pretty.xml
FelikZ 2/16

1
Observe que arrumado também pode formatar xml sem nenhum elemento raiz . Isso é útil para formatar através de um pipe, seções xml (por exemplo, extraídas de logs). echo '<x></x><y></y>' | tidy -xml -iq
Marinos Um

157

xmllint --format yourxmlfile.xml

xmllint é uma ferramenta XML de linha de comando e está incluída em libxml2( http://xmlsoft.org/ ).

==================================================

Nota: Se você não tiver libxml2instalado, poderá instalá-lo fazendo o seguinte:

CentOS

cd /tmp
wget ftp://xmlsoft.org/libxml2/libxml2-2.8.0.tar.gz
tar xzf libxml2-2.8.0.tar.gz
cd libxml2-2.8.0/
./configure
make
sudo make install
cd

Ubuntu

sudo apt-get install libxml2-utils

Cygwin

apt-cyg install libxml2

Mac OS

Para instalar isso no MacOS com o Homebrew, basta: brew install libxml2

Git

Também disponível no Git se você deseja o código: git clone git://git.gnome.org/libxml2


4
A resposta de sputnick contém essas informações, mas a resposta de crmpicco é a resposta mais útil aqui para a pergunta geral sobre como imprimir bastante XML.
Seth Difley

2
podemos escrever a saída xml formatada para outro arquivo xml e usá-la .. por exemplo: xmllint --format yourxmlfile.xml >> new-file.xml
LearnToLive

2
No Ubuntu 16.04, você pode usar o seguinte:sudo apt-get install libxml2-utils
Melle

Isso funciona no Windows também; gitpara Windows, o download instala até uma versão recente do xmllint. Exemplo:"C:\Program Files\Git\usr\bin\xmllint.exe" --format QCScaper.test@borland.com.cds.xml > QCScaper.test@borland.com.pretty-printed.cds.xml
Jeroen Wiert Pluimers

41

Você também pode usar o arrumado , que pode precisar ser instalado primeiro (por exemplo, no Ubuntu: sudo apt-get install tidy).

Para isso, você emitirá algo como o seguinte:

tidy -xml -i your-file.xml > output.xml

Nota: possui muitos sinalizadores de legibilidade adicionais, mas o comportamento de quebra de linha é um pouco irritante para desemaranhar ( http://tidy.sourceforge.net/docs/quickref.html ).


1
Útil, porque não consegui obter xmllint para adicionar quebras de linha a um arquivo xml de linha única. Obrigado!
Xlttj

tidyfunciona bem para mim também. Ao contrário hxnormalize, isso feito na verdade fecha a <body>etiqueta.
Sridhar Sarnobat

9
BTW, aqui estão algumas opções que eu encontrei útil: tidy --indent yes --indent-spaces 4 --indent-attributes yes --wrap-attributes yes --input-xml yes --output-xml yes < InFile.xml > OutFile.xml.
21716 Victor Yarema

2
Ótima dica @VictorYarema. Eu combinei com pygmentize e acrescentou que para o meu .bashrc: alias prettyxml='tidy --indent yes --indent-spaces 4 --indent-attributes yes --wrap-attributes yes --input-xml yes --output-xml yes | pygmentize -l xml' e, em seguida, podecurl url | prettyxml
Lobo Net

13

Você não mencionou um arquivo, portanto, suponho que você queira fornecer a sequência XML como entrada padrão na linha de comando. Nesse caso, faça o seguinte:

$ echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' | xmllint --format -

12

Sem instalar nada no macOS / na maioria dos Unix.

Usar tidy

cat filename.xml | tidy -xml -iq

Redirecionar a visualização de um arquivo com cat para organizar a especificação do tipo de arquivo xml e recuar enquanto a saída silenciosa suprimirá a saída de erro. JSON também trabalha com -json.


1
Você não precisa a catpasso: tidy -xml -iq filename.xml. Além disso, você pode tidy -xml -iq filename.xmlusar a -mopção de modificar o arquivo original ...
janniks em 3/03

10

Formatação de suporte xmllint no local :

for f in *.xml; do xmllint -o $f --format $f; done

Como Daniel Veillard escreveu:

Eu acho que xmllint -o tst.xml --format tst.xml deve ser seguro, pois o analisador carregará totalmente a entrada em uma árvore antes de abrir a saída para serializá-la.

O nível de recuo é controlado pela XMLLINT_INDENTvariável de ambiente, que é, por padrão, 2 espaços. Exemplo de como mudar o recuo para 4 espaços:

XMLLINT_INDENT='    '  xmllint -o out.xml --format in.xml

Você pode ter falta de --recoveropção quando seus documentos XML estão quebrados. Ou tente um analisador HTML fraco com saída XML estrita:

xmllint --html --xmlout <in.xml >out.xml

--nsclean, --nonet, --nocdata, --noblanksEtc., podem ser úteis. Leia a página do manual.

apt-get install libxml2-utils
apt-cyg install libxml2
brew install libxml2

2

Levei uma eternidade para encontrar algo que funcione no meu mac. Aqui está o que funcionou para mim:

brew install xmlformat
cat unformatted.html | xmlformat

1
Minha resposta acima funciona em um mac
jasonleonhard 04/04

1

Eu gostaria de adicionar uma solução Bash pura, pois não é "difícil" fazê-lo manualmente, e às vezes você não deseja instalar uma ferramenta extra para fazer o trabalho.

#!/bin/bash

declare -i currentIndent=0
declare -i nextIncrement=0
while read -r line ; do
  currentIndent+=$nextIncrement
  nextIncrement=0
  if [[ "$line" == "</"* ]]; then # line contains a closer, just decrease the indent
    currentIndent+=-1
  else
    dirtyStartTag="${line%%>*}"
    dirtyTagName="${dirtyStartTag%% *}"
    tagName="${dirtyTagName//</}"
    # increase indent unless line contains closing tag or closes itself
    if [[ ! "$line" =~ "</$tagName>" && ! "$line" == *"/>"  ]]; then
      nextIncrement+=1
    fi
  fi

  # print with indent
  printf "%*s%s" $(( $currentIndent * 2 )) # print spaces for the indent count
  echo $line
done <<< "$(cat - | sed 's/></>\n</g')" # separate >< with a newline

Cole-o em um arquivo de script e insira o xml. Isso pressupõe que o xml esteja em uma única linha e que não haja espaços extras em nenhum lugar. Pode-se facilmente adicionar alguns extras \s*às expressões regulares para corrigir isso.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.