Câu trả lời:
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 gần đây, được cập nhật và bao gồm một chức năng in đẹp
import lxml.etree as etree
x = etree.parse("filename")
print etree.tostring(x, pretty_print=True)
Kiểm tra hướng dẫn lxml: http://lxml.de/tutorial.html
aptitude install
đi. Trong OS / X tôi không chắc chắn.
print(etree.tostring(x, pretty_print=True, encoding="unicode"))
. Có thể ghi vào một tệp đầu ra chỉ trong một dòng, không cần biến trung gian:etree.parse("filename").write("outputfile", encoding="utf-8")
Một giải pháp khác là mượn chức năng nàyindent
, để sử dụng với thư viện ElementTree được tích hợp sẵn trong Python từ 2.5. Đây là những gì sẽ trông như:
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])
để ghi vào tệp ( tree
là ví dụ ElementTree).
tree = ElementTree.parse('file) ; root = tree.getroot() ; indent(root); tree.write('Out.xml');
Đây là giải pháp (hacky?) Của tôi để giải quyết vấn đề nút văn bản xấu xí.
uglyXml = doc.toprettyxml(indent=' ')
text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)
prettyXml = text_re.sub('>\g<1></', uglyXml)
print prettyXml
Đoạn mã trên sẽ tạo ra:
<?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>
Thay vì điều này:
<?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>
Disclaimer: Có lẽ có một số hạn chế.
re.compile
trước khi sub
hoạt động (tôi đã sử dụng re.findall()
hai lần zip
và một for
vòng lặp với str.replace()
...)
Như những người khác đã chỉ ra, lxml có một máy in đẹp được tích hợp sẵn.
Mặc dù vậy, hãy lưu ý rằng theo mặc định, nó thay đổi các phần CDATA thành văn bản bình thường, có thể có kết quả khó chịu.
Đây là một hàm Python bảo tồn tệp đầu vào và chỉ thay đổi thụt lề (chú ý strip_cdata=False
). Hơn nữa, nó đảm bảo đầu ra sử dụng UTF-8 làm mã hóa thay vì ASCII mặc định (chú ý 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')
Ví dụ sử dụng:
prettyPrintXml('some_folder/some_file.xml')
BeautifulSoup có một prettify()
phương pháp dễ sử dụng .
Nó thụt lề một không gian cho mỗi cấp độ thụt. Nó hoạt động tốt hơn nhiều so với beautiful_print của lxml và ngắn và ngọt ngào.
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?
Nếu bạn có xmllint
bạn có thể sinh ra một quy trình con và sử dụng nó. xmllint --format <file>
khá - in XML đầu vào của nó thành đầu ra tiêu chuẩn.
Lưu ý rằng phương pháp này sử dụng một chương trình bên ngoài để python, khiến nó bị hack.
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))
Tôi đã cố gắng chỉnh sửa câu trả lời của "ade" ở trên, nhưng Stack Overflow sẽ không cho phép tôi chỉnh sửa sau khi ban đầu tôi đã cung cấp phản hồi ẩn danh. Đây là phiên bản ít lỗi hơn của chức năng để in một 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 += ' '
Nếu bạn đang sử dụng triển khai DOM, mỗi loại có một hình thức in ấn đẹp riêng:
# 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)
Nếu bạn đang sử dụng một cái gì đó khác mà không có máy in đẹp của riêng nó - hoặc những máy in đẹp đó không hoàn toàn làm theo cách bạn muốn - có lẽ bạn phải viết hoặc phân lớp serializer của riêng bạn.
Tôi đã có một số vấn đề với bản in đẹp của minidom. Tôi sẽ nhận được UnicodeError bất cứ khi nào tôi thử in một tài liệu với các ký tự bên ngoài mã hóa đã cho, ví dụ nếu tôi có β trong tài liệu và tôi đã thử doc.toprettyxml(encoding='latin-1')
. Đây là cách giải quyết của tôi cho nó:
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)
Nó sẽ không thêm dấu cách hoặc dòng mới bên trong các nút văn bản, trừ khi bạn yêu cầu nó với:
indent(mystring, indent_text = True)
Bạn có thể chỉ định đơn vị thụt đầu dòng nên là gì và dòng mới sẽ như thế nào.
pretty_xml_string = indent(
ugly_xml_string,
indentation = ' ',
newline = '\r\n'
)
Tài liệu trên trang chủ http://www.yattag.org .
Tôi đã viết một giải pháp để duyệt qua ElementTree hiện có và sử dụng văn bản / đuôi để thụt lề như người ta thường mong đợi.
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 in đẹp cho python trông khá tốt cho nhiệm vụ này. (Được đặt tên phù hợp, quá.)
Một cách khác là sử dụng pyXML , có chức năng PrettyPrint .
HTTPError: 404 Client Error: Not Found for url: https://pypi.org/simple/xmlpp/
Nghĩ rằng dự án đang ở trên gác mái ngày nay, xấu hổ.
Đây là một giải pháp Python3 giúp loại bỏ vấn đề dòng mới xấu xí (hàng tấn khoảng trắng) và nó chỉ sử dụng các thư viện tiêu chuẩn không giống như hầu hết các triển khai khác.
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)
Tôi tìm thấy làm thế nào để khắc phục vấn đề dòng mới phổ biến ở đây .
Bạn có thể sử dụng thư viện bên ngoài phổ biến xmltodict , unparse
và pretty=True
bạn sẽ nhận được kết quả tốt nhất:
xmltodict.unparse(
xmltodict.parse(my_xml), full_document=False, pretty=True)
full_document=False
chống lại <?xml version="1.0" encoding="UTF-8"?>
ở đầu.
Hãy xem mô-đun vkbeautify .
Nó là phiên bản python của plugin javascript / nodejs rất phổ biến của tôi có cùng tên. Nó có thể in / thu nhỏ văn bản XML, JSON và CSS. Đầu vào và đầu ra có thể là chuỗi / tệp trong bất kỳ kết hợp nào. Nó rất nhỏ gọn và không có bất kỳ sự phụ thuộc nào.
Ví dụ :
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')
Một thay thế nếu bạn không muốn phải lặp lại, có thư viện xmlpp.py với get_pprint()
chức năng. Nó hoạt động tốt và mượt mà cho các trường hợp sử dụng của tôi, mà không phải lặp lại thành một đối tượng ElementTree lxml.
Bạn có thể thử biến thể này ...
Cài đặt BeautifulSoup
và các lxml
thư viện phụ trợ (trình phân tích cú pháp):
user$ pip3 install lxml bs4
Xử lý tài liệu XML của bạn:
from bs4 import BeautifulSoup
with open('/path/to/file.xml', 'r') as doc:
for line in doc:
print(BeautifulSoup(line, 'lxml-xml').prettify())
'lxml'
sử dụng trình phân tích cú pháp HTML của lxml - xem tài liệu BS4 . Bạn cần 'xml'
hoặc 'lxml-xml'
cho trình phân tích cú pháp XML.
lxml’s XML parser BeautifulSoup(markup, "lxml-xml") BeautifulSoup(markup, "xml")
lxml-xml
), và sau đó họ đã tiến hành downvote nó cùng ngày. Tôi đã gửi đơn khiếu nại chính thức tới S / O nhưng họ từ chối điều tra. Dù sao, tôi đã từ chối "giả mạo" câu trả lời của mình, giờ đây nó lại chính xác (và chỉ định lxml-xml
như ban đầu đã làm). Cảm ơn bạn.
Tôi đã có vấn đề này và giải quyết nó như thế này:
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)
Trong mã của tôi phương thức này được gọi như thế này:
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!")
Điều này chỉ hoạt động vì etree theo mặc định sử dụng two spaces
để thụt lề, mà tôi không thấy rất nhấn mạnh vào vết lõm và do đó không đẹp. Tôi không thể đặt bất kỳ cài đặt nào cho etree hoặc tham số cho bất kỳ chức năng nào để thay đổi thụt lề etree tiêu chuẩn. Tôi thích cách dễ dàng sử dụng etree, nhưng điều này thực sự làm tôi khó chịu.
Để chuyển đổi toàn bộ tài liệu xml thành tài liệu xml đẹp
(ví dụ: giả sử bạn đã giải nén [giải nén] tệp LibreOffice Writer .odt hoặc .ods và bạn muốn chuyển đổi tệp "content.xml" xấu xí thành một tệp đẹp cho kiểm soát phiên bản git tự động và git difftool
ing các tệp .odt / .ods , chẳng hạn như tôi đang triển khai ở đây )
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()
Tài liệu tham khảo:
- Nhờ câu trả lời của Ben Noland trên trang này đã đưa tôi đến gần hết.
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=' ',))
Nó hoạt động tốt cho xml với tiếng Trung!
Nếu vì một lý do nào đó bạn không thể chạm tay vào bất kỳ mô-đun Python nào mà người dùng khác đã đề cập, tôi đề xuất giải pháp sau cho 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)
Theo tôi biết, giải pháp này sẽ hoạt động trên các hệ thống dựa trên Unix có xmllint
cài đặt gói.
check_output
vì bạn không cần phải kiểm tra lỗi
Tôi đã giải quyết điều này bằng một số dòng mã, mở tệp, đi qua máng và thêm thụt lề, sau đó lưu lại. Tôi đã làm việc với các tệp xml nhỏ và không muốn thêm phụ thuộc hoặc thêm thư viện để cài đặt cho người dùng. Dù sao, đây là những gì tôi đã kết thúc với:
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()
Nó hoạt động với tôi, có lẽ ai đó sẽ sử dụng nó :)