Come stampare abbastanza XML dalla riga di comando?


528

Correlati: Come posso stampare in modo JSON in script shell (unix)?

Esiste uno script di shell (unix) per formattare XML in forma leggibile dall'uomo?

Fondamentalmente, voglio che trasformi quanto segue:

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

... in qualcosa del genere:

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

1
Per essere xmllintdisponibili sui sistemi Debian, è necessario installare il pacchetto libxml2-utils( libxml2non fornisce questo strumento, almeno non su Debian 5.0 "Lenny" e 6.0 "Squeeze").
twonkeys,

Risposte:


909

libxml2-utils

Questa utility viene fornita con libxml2-utils:

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

Perl XML::Twig

Questo comando viene fornito con XML :: Twig modulo, a volte xml-twig-toolspacchetto:

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

xmlstarlet

Questo comando viene fornito con xmlstarlet:

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

tidy

Controlla il tidypacchetto:

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

Pitone

Python xml.dom.minidompuò formattare XML (sia python2 che 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

Hai bisogno di saxon-lint:

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

saxon-HE

Hai bisogno di 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'

Buona, risposta rapida. La prima opzione sembra che sarà più onnipresente nelle installazioni moderne * nix. Un punto minore; ma può essere chiamato senza lavorare attraverso un file intermedio? Cioè echo '<xml .. />' | xmllint --some-read-from-stdn-option?
svidgen,

Il pacchetto è libxml2-utilsnel mio bellissimo Ubuntu.
franzlorenzon,

1
Si noti che "cat data.xml | xmllint --format - | tee data.xml" non funziona. Sul mio sistema a volte funzionava con file piccoli, ma troncava sempre file enormi. Se vuoi davvero fare qualcosa sul posto leggi backreference.org/2011/01/29/in-place-editing-of-files
user1346466

1
Per risolvere UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 805: ordinal not in range(128)in versione Python si desidera definire 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,

1
Nota che tidy può anche formattare xml senza alcun elemento root . Questo è utile per formattare attraverso una pipe, sezioni xml (ad es. Estratte dai registri). echo '<x></x><y></y>' | tidy -xml -iq
Marinos Il

157

xmllint --format yourxmlfile.xml

xmllint è uno strumento XML da riga di comando ed è incluso in libxml2( http://xmlsoft.org/ ).

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

Nota: se non è stato libxml2installato, è possibile installarlo nel modo seguente:

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

Per installarlo su MacOS con Homebrew basta fare: brew install libxml2

Idiota

Disponibile anche su Git se si desidera il codice: git clone git://git.gnome.org/libxml2


4
La risposta di sputnick contiene queste informazioni, ma la risposta di crmpicco è la risposta più utile qui alla domanda generale su come stampare abbastanza XML.
Seth Difley,

2
possiamo scrivere quell'output xml formattato su qualche altro file xml e usarlo .. ad esempio xmllint --format yourxmlfile.xml >> new-file.xml
LearnToLive

2
Su Ubuntu 16.04 puoi usare quanto segue:sudo apt-get install libxml2-utils
Melle

Funziona anche su Windows; gitper il download di Windows installa anche una versione recente di xmllint. Esempio:"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 il

41

Puoi anche usare tidy , che potrebbe essere necessario installare prima (es. Su Ubuntu: sudo apt-get install tidy).

Per questo, dovresti emettere qualcosa di simile al seguente:

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

Nota: ha molti flag di leggibilità aggiuntivi, ma il comportamento di a capo automatico è un po 'fastidioso da districare ( http://tidy.sourceforge.net/docs/quickref.html ).


1
Utile, perché non sono riuscito a ottenere xmllint per aggiungere interruzioni di riga a un file XML a riga singola. Grazie!
xlttj,

tidyfunziona bene anche per me. A differenza di hxnormalizeciò, effettivamente fatto chiude il <body>tag.
Sridhar Sarnobat,

9
BTW, qui ci sono alcune opzioni che ho trovato utile: tidy --indent yes --indent-spaces 4 --indent-attributes yes --wrap-attributes yes --input-xml yes --output-xml yes < InFile.xml > OutFile.xml.
Victor Yarema,

2
Ottimo consiglio @VictorYarema. L'ho combinato con pygmentize e l'ho aggiunto al mio .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 poi possocurl url | prettyxml
Net Wolf

13

Non hai menzionato un file, quindi presumo che tu voglia fornire la stringa XML come input standard sulla riga di comando. In tal caso, procedi come segue:

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

12

Senza installare nulla su macOS / la maggior parte di Unix.

Uso tidy

cat filename.xml | tidy -xml -iq

Il reindirizzamento della visualizzazione di un file con cat per riordinare specificando il tipo di file di xml e per rientrare mentre l'output silenzioso eliminerà l'output dell'errore. Anche JSON funziona con -json.


1
Non è necessario il catpasso: tidy -xml -iq filename.xml. Inoltre, puoi persino tidy -xml -iq filename.xmlusare l' -mopzione per modificare il file originale ...
Jan

10

xmllint supporta la formattazione sul posto :

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

Come ha scritto Daniel Veillard:

Penso che xmllint -o tst.xml --format tst.xml dovrebbe essere sicuro in quanto il parser caricherà completamente l'input in un albero prima di aprire l'output per serializzarlo.

Il livello di rientro è controllato dalla XMLLINT_INDENTvariabile d'ambiente che è di default 2 spazi. Esempio come modificare il rientro in 4 spazi:

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

Potresti avere carenze con l' --recoveropzione quando i documenti XML sono rotti. Oppure prova un parser HTML debole con output XML rigoroso:

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

--nsclean, --nonet, --nocdata, --noblanksEcc può essere utile. Leggi la pagina man.

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

2

Mi ci è voluta un'eternità per trovare qualcosa che funzioni sul mio mac. Ecco cosa ha funzionato per me:

brew install xmlformat
cat unformatted.html | xmlformat

1
La mia risposta sopra funziona su un mac
jasonleonhard il

1

Vorrei aggiungere una soluzione Bash pura, in quanto non è "così" farlo semplicemente a mano, e talvolta non vorrai installare uno strumento extra per fare il lavoro.

#!/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

Incollalo in un file di script e pipe nell'xml. Ciò presuppone che l'xml sia tutto su una riga e che non vi siano spazi extra da nessuna parte. Si potrebbe facilmente aggiungere qualche extra \s*alle regex per risolvere il problema.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.