Antworten:
import xml.dom.minidom
dom = xml.dom.minidom.parse(xml_fname) # or xml.dom.minidom.parseString(xml_string)
pretty_xml_as_string = dom.toprettyxml()
lxml ist neu, aktualisiert und enthält eine hübsche Druckfunktion
import lxml.etree as etree
x = etree.parse("filename")
print etree.tostring(x, pretty_print=True)
Schauen Sie sich das lxml-Tutorial an: http://lxml.de/tutorial.html
aptitude install
weg. Unter OS / X bin ich mir nicht sicher.
print(etree.tostring(x, pretty_print=True, encoding="unicode"))
. Das Schreiben in eine Ausgabedatei ist in nur einer Zeile möglich, es wird keine Zwischenvariable benötigt:etree.parse("filename").write("outputfile", encoding="utf-8")
Eine andere Lösung besteht darin, diese indent
Funktion zur Verwendung mit der ElementTree-Bibliothek auszuleihen, die seit 2.5 in Python integriert ist. So würde das aussehen:
from xml.etree import ElementTree
def indent(elem, level=0):
i = "\n" + level*" "
j = "\n" + (level-1)*" "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for subelem in elem:
indent(subelem, level+1)
if not elem.tail or not elem.tail.strip():
elem.tail = j
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = j
return elem
root = ElementTree.parse('/tmp/xmlfile').getroot()
indent(root)
ElementTree.dump(root)
tree.write([filename])
in eine Datei schreiben können (dies tree
ist die ElementTree-Instanz).
tree = ElementTree.parse('file) ; root = tree.getroot() ; indent(root); tree.write('Out.xml');
Hier ist meine (hackige?) Lösung, um das hässliche Textknotenproblem zu umgehen.
uglyXml = doc.toprettyxml(indent=' ')
text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)
prettyXml = text_re.sub('>\g<1></', uglyXml)
print prettyXml
Der obige Code erzeugt:
<?xml version="1.0" ?>
<issues>
<issue>
<id>1</id>
<title>Add Visual Studio 2005 and 2008 solution files</title>
<details>We need Visual Studio 2005/2008 project files for Windows.</details>
</issue>
</issues>
An Stelle von:
<?xml version="1.0" ?>
<issues>
<issue>
<id>
1
</id>
<title>
Add Visual Studio 2005 and 2008 solution files
</title>
<details>
We need Visual Studio 2005/2008 project files for Windows.
</details>
</issue>
</issues>
Haftungsausschluss: Es gibt wahrscheinlich einige Einschränkungen.
re.compile
vor der sub
Operation verwendet (ich habe sie re.findall()
zweimal verwendet zip
und eine for
Schleife mit str.replace()
...)
Wie andere betonten, ist in lxml ein hübscher Drucker eingebaut.
Beachten Sie jedoch, dass CDATA-Abschnitte standardmäßig in normalen Text geändert werden, was zu unangenehmen Ergebnissen führen kann.
Hier ist eine Python-Funktion, die die Eingabedatei beibehält und nur den Einzug ändert (beachten Sie das strip_cdata=False
). Außerdem wird sichergestellt, dass die Ausgabe UTF-8 als Codierung anstelle des Standard-ASCII verwendet (beachten Sie Folgendes encoding='utf-8'
):
from lxml import etree
def prettyPrintXml(xmlFilePathToPrettyPrint):
assert xmlFilePathToPrettyPrint is not None
parser = etree.XMLParser(resolve_entities=False, strip_cdata=False)
document = etree.parse(xmlFilePathToPrettyPrint, parser)
document.write(xmlFilePathToPrettyPrint, pretty_print=True, encoding='utf-8')
Anwendungsbeispiel:
prettyPrintXml('some_folder/some_file.xml')
BeautifulSoup hat eine einfach zu verwendende prettify()
Methode.
Es wird ein Leerzeichen pro Einrückungsstufe eingerückt. Es funktioniert viel besser als der hübsche Druck von lxml und ist kurz und bündig.
from bs4 import BeautifulSoup
bs = BeautifulSoup(open(xml_file), 'xml')
print bs.prettify()
bs4.FeatureNotFound: Couldn't find a tree builder with the features you requested: xml. Do you need to install a parser library?
Wenn Sie haben xmllint
, können Sie einen Unterprozess erzeugen und verwenden. xmllint --format <file>
druckt seine Eingabe-XML hübsch in die Standardausgabe.
Beachten Sie, dass diese Methode ein Programm außerhalb von Python verwendet, was es zu einer Art Hack macht.
def pretty_print_xml(xml):
proc = subprocess.Popen(
['xmllint', '--format', '/dev/stdin'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
)
(output, error_output) = proc.communicate(xml);
return output
print(pretty_print_xml(data))
Ich habe versucht, die Antwort von "ade" oben zu bearbeiten, aber Stack Overflow ließ mich nicht bearbeiten, nachdem ich ursprünglich anonym Feedback gegeben hatte. Dies ist eine weniger fehlerhafte Version der Funktion zum hübschen Drucken eines ElementTree.
def indent(elem, level=0, more_sibs=False):
i = "\n"
if level:
i += (level-1) * ' '
num_kids = len(elem)
if num_kids:
if not elem.text or not elem.text.strip():
elem.text = i + " "
if level:
elem.text += ' '
count = 0
for kid in elem:
indent(kid, level+1, count < num_kids - 1)
count += 1
if not elem.tail or not elem.tail.strip():
elem.tail = i
if more_sibs:
elem.tail += ' '
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
if more_sibs:
elem.tail += ' '
Wenn Sie eine DOM-Implementierung verwenden, verfügt jede über eine eigene integrierte Form des hübschen Druckens:
# minidom
#
document.toprettyxml()
# 4DOM
#
xml.dom.ext.PrettyPrint(document, stream)
# pxdom (or other DOM Level 3 LS-compliant imp)
#
serializer.domConfig.setParameter('format-pretty-print', True)
serializer.writeToString(document)
Wenn Sie etwas anderes ohne eigenen hübschen Drucker verwenden - oder diese hübschen Drucker tun es nicht ganz so, wie Sie es möchten -, müssen Sie wahrscheinlich Ihren eigenen Serialisierer schreiben oder unterordnen.
Ich hatte einige Probleme mit dem hübschen Druck von Minidom. Ich würde einen UnicodeError erhalten, wenn ich versuchte, ein Dokument mit Zeichen außerhalb der angegebenen Codierung hübsch zu drucken, z. B. wenn ich ein β in einem Dokument hatte und es versuchte doc.toprettyxml(encoding='latin-1')
. Hier ist meine Problemumgehung dafür:
def toprettyxml(doc, encoding):
"""Return a pretty-printed XML document in a given encoding."""
unistr = doc.toprettyxml().replace(u'<?xml version="1.0" ?>',
u'<?xml version="1.0" encoding="%s"?>' % encoding)
return unistr.encode(encoding, 'xmlcharrefreplace')
from yattag import indent
pretty_string = indent(ugly_string)
Es werden keine Leerzeichen oder Zeilenumbrüche in Textknoten hinzugefügt, es sei denn, Sie fragen danach mit:
indent(mystring, indent_text = True)
Sie können festlegen, wie die Einrückungseinheit sein soll und wie die neue Zeile aussehen soll.
pretty_xml_string = indent(
ugly_xml_string,
indentation = ' ',
newline = '\r\n'
)
Das Dokument befindet sich auf der Homepage von http://www.yattag.org .
Ich habe eine Lösung geschrieben, um durch einen vorhandenen ElementTree zu gehen und ihn mit Text / Schwanz einzurücken, wie man es normalerweise erwartet.
def prettify(element, indent=' '):
queue = [(0, element)] # (level, element)
while queue:
level, element = queue.pop(0)
children = [(level + 1, child) for child in list(element)]
if children:
element.text = '\n' + indent * (level+1) # for child open
if queue:
element.tail = '\n' + indent * queue[0][0] # for sibling open
else:
element.tail = '\n' + indent * (level-1) # for parent close
queue[0:0] = children # prepend so children come before siblings
XML Pretty Print für Python sieht für diese Aufgabe ziemlich gut aus. (Passend auch benannt.)
Eine Alternative ist die Verwendung von pyXML mit einer PrettyPrint-Funktion .
HTTPError: 404 Client Error: Not Found for url: https://pypi.org/simple/xmlpp/
Denken Sie, dass das Projekt heutzutage auf dem Dachboden ist, schade.
Hier ist eine Python3-Lösung, die das hässliche Newline-Problem (Tonnen von Leerzeichen) beseitigt und im Gegensatz zu den meisten anderen Implementierungen nur Standardbibliotheken verwendet.
import xml.etree.ElementTree as ET
import xml.dom.minidom
import os
def pretty_print_xml_given_root(root, output_xml):
"""
Useful for when you are editing xml data on the fly
"""
xml_string = xml.dom.minidom.parseString(ET.tostring(root)).toprettyxml()
xml_string = os.linesep.join([s for s in xml_string.splitlines() if s.strip()]) # remove the weird newline issue
with open(output_xml, "w") as file_out:
file_out.write(xml_string)
def pretty_print_xml_given_file(input_xml, output_xml):
"""
Useful for when you want to reformat an already existing xml file
"""
tree = ET.parse(input_xml)
root = tree.getroot()
pretty_print_xml_given_root(root, output_xml)
Ich habe hier herausgefunden, wie das häufig auftretende Newline-Problem behoben werden kann .
Sie können die beliebte externe Bibliothek xmltodict verwenden , mit unparse
und pretty=True
Sie erhalten das beste Ergebnis:
xmltodict.unparse(
xmltodict.parse(my_xml), full_document=False, pretty=True)
full_document=False
gegen <?xml version="1.0" encoding="UTF-8"?>
an der Spitze.
Schauen Sie sich das vkbeautify- Modul an.
Es ist eine Python-Version meines sehr beliebten Javascript / NodeJS-Plugins mit demselben Namen. Es kann XML-, JSON- und CSS-Text hübsch drucken / minimieren. Eingabe und Ausgabe können Zeichenfolge / Datei in beliebigen Kombinationen sein. Es ist sehr kompakt und hat keine Abhängigkeit.
Beispiele :
import vkbeautify as vkb
vkb.xml(text)
vkb.xml(text, 'path/to/dest/file')
vkb.xml('path/to/src/file')
vkb.xml('path/to/src/file', 'path/to/dest/file')
Eine Alternative, wenn Sie nicht erneut analysieren möchten, ist die Bibliothek xmlpp.py mit der get_pprint()
Funktion. Für meine Anwendungsfälle funktionierte es gut und reibungslos, ohne dass ein lxml-ElementTree-Objekt erneut analysiert werden musste.
Sie können diese Variante ausprobieren ...
Installieren Sie BeautifulSoup
die Backend- lxml
Bibliotheken (Parser):
user$ pip3 install lxml bs4
Verarbeiten Sie Ihr XML-Dokument:
from bs4 import BeautifulSoup
with open('/path/to/file.xml', 'r') as doc:
for line in doc:
print(BeautifulSoup(line, 'lxml-xml').prettify())
'lxml'
verwendet den HTML- Parser von lxml - siehe BS4- Dokumente . Sie benötigen 'xml'
oder 'lxml-xml'
für den XML-Parser.
lxml’s XML parser BeautifulSoup(markup, "lxml-xml") BeautifulSoup(markup, "xml")
lxml-xml
) manipuliert , und dann haben sie sie noch am selben Tag abgelehnt. Ich habe eine offizielle Beschwerde bei S / O eingereicht, aber sie haben sich geweigert, Nachforschungen anzustellen. Wie auch immer, ich habe seitdem meine Antwort "manipuliert", die jetzt wieder korrekt ist (und lxml-xml
wie ursprünglich angegeben angibt ). Vielen Dank.
Ich hatte dieses Problem und löste es so:
def write_xml_file (self, file, xml_root_element, xml_declaration=False, pretty_print=False, encoding='unicode', indent='\t'):
pretty_printed_xml = etree.tostring(xml_root_element, xml_declaration=xml_declaration, pretty_print=pretty_print, encoding=encoding)
if pretty_print: pretty_printed_xml = pretty_printed_xml.replace(' ', indent)
file.write(pretty_printed_xml)
In meinem Code heißt diese Methode folgendermaßen:
try:
with open(file_path, 'w') as file:
file.write('<?xml version="1.0" encoding="utf-8" ?>')
# create some xml content using etree ...
xml_parser = XMLParser()
xml_parser.write_xml_file(file, xml_root, xml_declaration=False, pretty_print=True, encoding='unicode', indent='\t')
except IOError:
print("Error while writing in log file!")
Dies funktioniert nur, weil etree standardmäßig two spaces
zum Einrücken verwendet , was die Einrückung nicht sehr hervorhebt und daher nicht schön ist. Ich konnte keine Einstellung für etree oder Parameter für eine Funktion zum Ändern des Standard-etree-Einzugs festlegen. Mir gefällt, wie einfach es ist, etree zu verwenden, aber das hat mich wirklich geärgert.
Zum Konvertieren eines gesamten XML-Dokuments in ein hübsches XML-Dokument
(z. B. vorausgesetzt, Sie haben eine .odt- oder .ods-Datei von LibreOffice Writer extrahiert [entpackt] und möchten die hässliche Datei "content.xml" in eine hübsche Datei konvertieren automatisierte Git-Versionskontrolle und git difftool
Ing von .odt / .ods-Dateien , wie ich sie hier implementiere )
import xml.dom.minidom
file = open("./content.xml", 'r')
xml_string = file.read()
file.close()
parsed_xml = xml.dom.minidom.parseString(xml_string)
pretty_xml_as_string = parsed_xml.toprettyxml()
file = open("./content_new.xml", 'w')
file.write(pretty_xml_as_string)
file.close()
Referenzen:
- Dank der Antwort von Ben Noland auf dieser Seite, die mich den größten Teil des Weges dorthin gebracht hat.
from lxml import etree
import xml.dom.minidom as mmd
xml_root = etree.parse(xml_fiel_path, etree.XMLParser())
def print_xml(xml_root):
plain_xml = etree.tostring(xml_root).decode('utf-8')
urgly_xml = ''.join(plain_xml .split())
good_xml = mmd.parseString(urgly_xml)
print(good_xml.toprettyxml(indent=' ',))
Es funktioniert gut für die XML mit Chinesisch!
Wenn Sie aus irgendeinem Grund keines der von anderen Benutzern erwähnten Python-Module in die Hände bekommen können, empfehle ich die folgende Lösung für Python 2.7:
import subprocess
def makePretty(filepath):
cmd = "xmllint --format " + filepath
prettyXML = subprocess.check_output(cmd, shell = True)
with open(filepath, "w") as outfile:
outfile.write(prettyXML)
Soweit ich weiß, funktioniert diese Lösung auf Unix-basierten Systemen, auf denen das xmllint
Paket installiert ist.
check_output
weil Sie keine Fehlerprüfung durchführen müssen
Ich löste dies mit einigen Codezeilen, öffnete die Datei, ging sie durch, fügte Einrückungen hinzu und speicherte sie dann erneut. Ich habe mit kleinen XML-Dateien gearbeitet und wollte keine Abhängigkeiten oder mehr Bibliotheken hinzufügen, die für den Benutzer installiert werden sollen. Wie auch immer, hier ist, was ich am Ende hatte:
f = open(file_name,'r')
xml = f.read()
f.close()
#Removing old indendations
raw_xml = ''
for line in xml:
raw_xml += line
xml = raw_xml
new_xml = ''
indent = ' '
deepness = 0
for i in range((len(xml))):
new_xml += xml[i]
if(i<len(xml)-3):
simpleSplit = xml[i:(i+2)] == '><'
advancSplit = xml[i:(i+3)] == '></'
end = xml[i:(i+2)] == '/>'
start = xml[i] == '<'
if(advancSplit):
deepness += -1
new_xml += '\n' + indent*deepness
simpleSplit = False
deepness += -1
if(simpleSplit):
new_xml += '\n' + indent*deepness
if(start):
deepness += 1
if(end):
deepness += -1
f = open(file_name,'w')
f.write(new_xml)
f.close()
Es funktioniert für mich, vielleicht wird jemand davon Gebrauch machen :)