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.