Wie drucke ich XML hübsch über die Befehlszeile?

528

Verwandte: Wie kann ich JSON in (Unix) Shell-Skript hübsch drucken?

Gibt es ein (Unix-) Shell-Skript zum Formatieren von XML in lesbarer Form?

Grundsätzlich möchte ich, dass es Folgendes transformiert:

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

... in so etwas:

<root>
    <foo a="b">lorem</foo>
    <bar value="ipsum" />
</root>
svidgen
quelle
1
Um xmllintauf Debian-Systemen verfügbar zu sein, müssen Sie das Paket installieren libxml2-utils( libxml2bietet dieses Tool nicht an, zumindest nicht unter Debian 5.0 "Lenny" und 6.0 "Squeeze").
Zwei Schlüssel

Antworten:

909

libxml2-utils

Dieses Dienstprogramm enthält libxml2-utils:

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

Perls XML::Twig

Dieser Befehl wird mit XML :: Twig geliefert Modul, manchmal xml-twig-toolsPaket:

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

xmlstarlet

Dieser Befehl enthält xmlstarlet:

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

tidy

Überprüfen Sie das tidyPaket:

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

Python

Pythons xml.dom.minidomkönnen XML formatieren (sowohl Python2 als auch 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

Sie benötigen saxon-lint:

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

saxon-HE

Sie benötigen 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'
Gilles Quenot
quelle
Gute, schnelle Antwort. Die erste Option scheint bei modernen * nix-Installationen allgegenwärtiger zu sein. Ein kleiner Punkt; Aber kann es aufgerufen werden, ohne eine Zwischendatei durchzuarbeiten? Dh echo '<xml .. />' | xmllint --some-read-from-stdn-option?
Svidgen
Das Paket ist libxml2-utilsin meinem schönen Ubuntu.
Franzlorenzon
1
Beachten Sie, dass "cat data.xml | xmllint --format - | tee data.xml" nicht funktioniert. Auf meinem System funktionierte es manchmal für kleine Dateien, aber immer für große Dateien. Wenn Sie wirklich etwas an Ort und Stelle tun möchten, lesen Sie backreference.org/2011/01/29/in-place-editing-of-files
user1346466
1
Um UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 805: ordinal not in range(128)in Python-Version zu lösen , möchten Sie definieren 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
Beachten Sie, dass tidy auch XML ohne Root-Element formatieren kann . Dies ist nützlich, um XML-Abschnitte (z. B. aus Protokollen extrahiert) über eine Pipe zu formatieren. echo '<x></x><y></y>' | tidy -xml -iq
Marinos An
157

xmllint --format yourxmlfile.xml

xmllint ist ein Befehlszeilen-XML-Tool und in libxml2( http://xmlsoft.org/ ) enthalten.

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

Hinweis: Wenn Sie nicht libxml2installiert haben, können Sie es wie folgt installieren:

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

Um dies unter Homebrew unter MacOS zu installieren, gehen Sie einfach wie folgt vor: brew install libxml2

Git

Auch auf Git verfügbar, wenn Sie den Code möchten: git clone git://git.gnome.org/libxml2

crmpicco
quelle
4
Die Antwort von sputnick enthält diese Informationen, aber die Antwort von crmpicco ist hier die nützlichste Antwort auf die allgemeine Frage, wie man XML hübsch druckt.
Seth Difley
2
Wir können diese formatierte XML-Ausgabe in eine andere XML-Datei schreiben und diese verwenden. zB xmllint --format yourxmlfile.xml >> new-file.xml
LearnToLive
2
Unter Ubuntu 16.04 können Sie Folgendes verwenden:sudo apt-get install libxml2-utils
Melle
Dies funktioniert auch unter Windows. gitFür Windows- Download wird sogar eine aktuelle Version von installiert xmllint. Beispiel:"C:\Program Files\Git\usr\bin\xmllint.exe" --format [email protected] > [email protected]
Jeroen Wiert Pluimers
41

Sie können auch tidy verwenden , das möglicherweise zuerst installiert werden muss (z. B. unter Ubuntu: sudo)apt-get install tidy ).

Dazu würden Sie etwa Folgendes ausgeben:

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

Hinweis: Es gibt viele zusätzliche Lesbarkeitsflags, aber das Verhalten beim Umbrechen von Wörtern ist etwas ärgerlich ( http://tidy.sourceforge.net/docs/quickref.html ).

Matanster
quelle
1
Hilfreich, da ich xmllint nicht dazu bringen konnte, einer XML-Datei mit einer einzelnen Zeile Zeilenumbrüche hinzuzufügen. Vielen Dank!
xlttj
tidyfunktioniert auch gut für mich. Im Gegensatz hxnormalizedazu schließt dies das <body>Tag tatsächlich .
Sridhar Sarnobat
9
Übrigens, hier sind einige Optionen, die ich nützlich gefunden habe : 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
Toller Tipp @VictorYarema. Ich kombinierte es mit pygementize und fügte es meinem .bashrc hinzu: alias prettyxml='tidy --indent yes --indent-spaces 4 --indent-attributes yes --wrap-attributes yes --input-xml yes --output-xml yes | pygmentize -l xml' und kann danncurl url | prettyxml
Net Wolf
13

Sie haben keine Datei erwähnt, daher gehe ich davon aus, dass Sie die XML-Zeichenfolge als Standardeingabe in der Befehlszeile bereitstellen möchten. Gehen Sie in diesem Fall wie folgt vor:

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

Ohne etwas unter macOS / den meisten Unix zu installieren.

Verwenden tidy

cat filename.xml | tidy -xml -iq

Wenn Sie das Anzeigen einer Datei mit cat umleiten, um den Dateityp von xml anzugeben und bei leiser Ausgabe einzurücken, wird die Fehlerausgabe unterdrückt. JSON funktioniert auch mit -json.

jasonleonhard
quelle
1
Sie brauchen den catSchritt nicht : tidy -xml -iq filename.xml. Sie können auch tidy -xml -iq filename.xmldie -mOption verwenden, um die Originaldatei zu ändern ...
janniks
10

xmllint unterstützt die Formatierung vor Ort :

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

Wie Daniel Veillard geschrieben hat:

Ich denke, xmllint -o tst.xml --format tst.xml sollte sicher sein, da der Parser die Eingabe vollständig in einen Baum lädt, bevor er die Ausgabe öffnet, um sie zu serialisieren.

Die Einrückungsstufe wird durch die XMLLINT_INDENTUmgebungsvariable gesteuert , die standardmäßig 2 Leerzeichen beträgt. Beispiel für das Ändern des Einzugs in 4 Leerzeichen:

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

Möglicherweise fehlt --recoverIhnen die Option, wenn XML-Dokumente beschädigt sind. Oder versuchen Sie es mit einem schwachen HTML-Parser mit strenger XML-Ausgabe:

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

--nsclean, --nonet, --nocdata, --noblanksKann usw. nützlich sein. Manpage lesen.

apt-get install libxml2-utils
apt-cyg install libxml2
brew install libxml2
Gavenkoa
quelle
2

Ich habe ewig gebraucht, um etwas zu finden, das auf meinem Mac funktioniert. Folgendes hat bei mir funktioniert:

brew install xmlformat
cat unformatted.html | xmlformat
Sridhar Sarnobat
quelle
1
Meine Antwort oben funktioniert auf einem Mac
Jasonleonhard
1

Ich möchte eine reine Bash-Lösung hinzufügen, da es nicht so schwierig ist, dies einfach von Hand zu tun, und manchmal möchten Sie kein zusätzliches Tool installieren, um die Aufgabe zu erledigen.

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

Fügen Sie es in eine Skriptdatei ein und leiten Sie es in die XML-Datei ein. Dies setzt voraus, dass sich die XML-Datei in einer Zeile befindet und nirgendwo zusätzliche Leerzeichen vorhanden sind. Man könnte \s*den regulären Ausdrücken leicht etwas mehr hinzufügen, um das zu beheben.

leondepeon
quelle