Jawaban:
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 baru-baru ini, diperbarui, dan mencakup fungsi cetak yang cantik
import lxml.etree as etree
x = etree.parse("filename")
print etree.tostring(x, pretty_print=True)
Lihatlah tutorial lxml: http://lxml.de/tutorial.html
aptitude install
jauh. Di bawah OS / X saya tidak yakin.
print(etree.tostring(x, pretty_print=True, encoding="unicode"))
. Menulis ke file output dimungkinkan hanya dalam satu baris, tidak ada variabel perantara yang diperlukan:etree.parse("filename").write("outputfile", encoding="utf-8")
Solusi lain adalah meminjam fungsi iniindent
, untuk digunakan dengan pustaka ElementTree yang dibangun di dalam Python sejak 2.5. Ini akan terlihat seperti apa:
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])
untuk menulis ke file ( tree
menjadi instance ElementTree).
tree = ElementTree.parse('file) ; root = tree.getroot() ; indent(root); tree.write('Out.xml');
Inilah solusi (peretasan?) Saya untuk mengatasi masalah simpul teks yang jelek.
uglyXml = doc.toprettyxml(indent=' ')
text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)
prettyXml = text_re.sub('>\g<1></', uglyXml)
print prettyXml
Kode di atas akan menghasilkan:
<?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>
Alih-alih ini:
<?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>
Penafian: Mungkin ada beberapa batasan.
re.compile
sebelum sub
operasi (saya menggunakan re.findall()
dua kali, zip
dan satu for
loop dengan str.replace()
...)
Seperti yang ditunjukkan orang lain, lxml memiliki printer yang cukup bawaan.
Ketahuilah bahwa secara default ia mengubah bagian CDATA menjadi teks biasa, yang dapat memberikan hasil buruk.
Berikut adalah fungsi Python yang mempertahankan file input dan hanya mengubah indentasi (perhatikan strip_cdata=False
). Selain itu memastikan bahwa output menggunakan UTF-8 sebagai pengkodean bukan ASCII default (perhatikan 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')
Contoh penggunaan:
prettyPrintXml('some_folder/some_file.xml')
BeautifulSoup memiliki cara yang mudah digunakan prettify()
.
Itu indentasi satu ruang per tingkat lekukan. Ini bekerja jauh lebih baik daripada pretty_print lxml dan pendek dan manis.
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?
Jika sudah, xmllint
Anda dapat menelurkan subproses dan menggunakannya.xmllint --format <file>
cukup mencetak inputnya XML ke output standar.
Perhatikan bahwa metode ini menggunakan program eksternal ke python, yang membuatnya menjadi semacam peretasan.
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))
Saya mencoba mengedit jawaban "ade" di atas, tetapi Stack Overflow tidak akan membiarkan saya mengedit setelah saya awalnya memberikan umpan balik secara anonim. Ini adalah versi fungsi yang kurang buggy untuk mencetak ElementTree dengan cantik.
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 += ' '
Jika Anda menggunakan implementasi DOM, masing-masing memiliki bentuk built-in pencetakan cantik:
# 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)
Jika Anda menggunakan sesuatu yang lain tanpa printer cantiknya sendiri - atau printer cantik itu tidak cukup melakukannya seperti yang Anda inginkan - Anda mungkin harus menulis atau mensubklasifikasikan serialiser Anda sendiri.
Saya memiliki beberapa masalah dengan cetakan cantik minidom. Saya akan mendapatkan UnicodeError setiap kali saya mencoba cukup mencetak dokumen dengan karakter di luar pengkodean yang diberikan, misalnya jika saya memiliki β dalam dokumen dan saya mencoba doc.toprettyxml(encoding='latin-1')
. Inilah solusi saya untuk itu:
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)
Itu tidak akan menambahkan spasi atau baris baru di dalam simpul teks, kecuali jika Anda memintanya dengan:
indent(mystring, indent_text = True)
Anda dapat menentukan seperti apa unit indentasi itu dan seperti apa baris baru itu.
pretty_xml_string = indent(
ugly_xml_string,
indentation = ' ',
newline = '\r\n'
)
Doc ada di beranda http://www.yattag.org .
Saya menulis solusi untuk berjalan melalui ElementTree yang ada dan menggunakan teks / ekor untuk membuat indentasi seperti yang biasanya diharapkan.
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
Cetak cukup XML untuk python terlihat cukup bagus untuk tugas ini. (Dinamai dengan tepat juga.)
Alternatifnya adalah menggunakan pyXML , yang memiliki fungsi PrettyPrint .
HTTPError: 404 Client Error: Not Found for url: https://pypi.org/simple/xmlpp/
Bayangkan proyek itu ada di loteng saat ini, sayang.
Anda dapat menggunakan perpustakaan eksternal xmltodict populer , dengan unparse
dan pretty=True
Anda akan mendapatkan hasil terbaik:
xmltodict.unparse(
xmltodict.parse(my_xml), full_document=False, pretty=True)
full_document=False
melawan <?xml version="1.0" encoding="UTF-8"?>
di atas.
Berikut adalah solusi Python3 yang menghilangkan masalah baris baru yang jelek (ton spasi), dan itu hanya menggunakan perpustakaan standar tidak seperti kebanyakan implementasi lainnya.
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)
Saya menemukan cara memperbaiki masalah baris baru yang umum di sini .
Lihatlah modul vkbeautify .
Ini adalah versi python dari plugin javascript / nodejs saya yang sangat populer dengan nama yang sama. Ini bisa mencetak / memperkecil XML, JSON dan teks CSS. Input dan output dapat berupa string / file dalam kombinasi apa pun. Ini sangat kompak dan tidak memiliki ketergantungan.
Contoh :
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')
Alternatif jika Anda tidak ingin mengulang , ada perpustakaan xmlpp.py dengan get_pprint()
fungsinya. Ini bekerja dengan baik dan lancar untuk kasus penggunaan saya, tanpa harus mem-reparse ke objek ElementTree lxml.
Anda dapat mencoba variasi ini ...
Instal BeautifulSoup
dan lxml
pustaka backend (parser):
user$ pip3 install lxml bs4
Memproses dokumen XML Anda:
from bs4 import BeautifulSoup
with open('/path/to/file.xml', 'r') as doc:
for line in doc:
print(BeautifulSoup(line, 'lxml-xml').prettify())
'lxml'
menggunakan parser HTML lxml - lihat dokumen BS4 . Anda perlu 'xml'
atau 'lxml-xml'
untuk parser XML.
lxml’s XML parser BeautifulSoup(markup, "lxml-xml") BeautifulSoup(markup, "xml")
lxml-xml
), dan kemudian mereka melanjutkan untuk downvote pada hari yang sama. Saya mengajukan keluhan resmi ke S / O tetapi mereka menolak untuk menyelidiki. Lagi pula, saya telah sejak "merusak" jawaban saya, yang sekarang benar lagi (dan menentukan lxml-xml
seperti yang awalnya). Terima kasih.
Saya punya masalah ini dan menyelesaikannya seperti ini:
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)
Dalam kode saya metode ini disebut seperti ini:
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!")
Ini hanya berfungsi karena etree secara default menggunakan two spaces
indent, yang menurut saya tidak terlalu menekankan indentasi dan karenanya tidak cantik. Saya tidak dapat menentukan pengaturan etree atau parameter untuk fungsi apa pun untuk mengubah indentasi etree standar. Saya suka betapa mudahnya menggunakan etree, tapi ini benar-benar mengganggu saya.
Untuk mengonversi seluruh dokumen xml ke dokumen xml yang cantik
(mis: anggap Anda telah mengekstrak [unzip] file LibreOffice Writer .odt atau .ods, dan Anda ingin mengonversi file "content.xml" yang jelek ke file yang cukup untuk kontrol versi git otomatis dan git difftool
file .odt / .ods , seperti yang saya laksanakan di sini )
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()
Referensi:
- Terima kasih atas jawaban Ben Noland di halaman ini yang membuat saya hampir sampai ke sana.
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=' ',))
Ini bekerja dengan baik untuk xml dengan bahasa Mandarin!
Jika karena alasan tertentu Anda tidak bisa mendapatkan modul Python apa pun yang disebutkan pengguna lain, saya sarankan solusi berikut untuk 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)
Sejauh yang saya tahu, solusi ini akan bekerja pada sistem berbasis Unix yang memiliki xmllint
paket yang diinstal.
check_output
karena Anda tidak perlu melakukan pengecekan kesalahan
Saya memecahkan ini dengan beberapa baris kode, membuka file, melewatinya dan menambahkan lekukan, lalu menyimpannya lagi. Saya sedang bekerja dengan file xml kecil, dan tidak ingin menambahkan dependensi, atau lebih banyak perpustakaan untuk diinstal untuk pengguna. Bagaimanapun, inilah yang akhirnya saya dapatkan:
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()
Ini bekerja untuk saya, mungkin seseorang akan menggunakannya :)