Відповіді:
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 останній, оновлений і включає в себе гарну функцію друку
import lxml.etree as etree
x = etree.parse("filename")
print etree.tostring(x, pretty_print=True)
Перегляньте підручник lxml: http://lxml.de/tutorial.html
aptitude install
. В ОС / X я не впевнений.
print(etree.tostring(x, pretty_print=True, encoding="unicode"))
. Запис у вихідний файл можливий лише в одному рядку, не потрібно посередницької змінної:etree.parse("filename").write("outputfile", encoding="utf-8")
Ще одне рішення - запозичити цю indent
функцію для використання з бібліотекою ElementTree, вбудованою в Python з 2.5. Ось як це виглядатиме:
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])
для написання файлу (tree
це екземпляр ElementTree).
tree = ElementTree.parse('file) ; root = tree.getroot() ; indent(root); tree.write('Out.xml');
Ось моє (хакі?) Рішення для вирішення негарної проблеми з текстовим вузлом.
uglyXml = doc.toprettyxml(indent=' ')
text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)
prettyXml = text_re.sub('>\g<1></', uglyXml)
print prettyXml
Наведений вище код створює:
<?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>
Замість цього:
<?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>
Відмова: Мабуть, є деякі обмеження.
re.compile
до початку sub
роботи (я використовував re.findall()
двічі, zip
а for
петлю з str.replace()
...)
Як зазначали інші, у lxml вбудований гарний принтер.
Будьте в курсі, що за замовчуванням він змінює розділи CDATA на звичайний текст, що може мати неприємні результати.
Ось функція Python, яка зберігає вхідний файл і змінює лише відступи (помічайте strip_cdata=False
). Крім того, він гарантує, що вихід використовує UTF-8 як кодування замість ASCII за замовчуванням (зверніть увагу 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')
Приклад використання:
prettyPrintXml('some_folder/some_file.xml')
BeautifulSoup має простий у використанні prettify()
метод.
Відступає один пробіл на рівень відступу. Він працює набагато краще, ніж досить-відбиток lxml та є коротким та солодким.
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?
Якщо у вас є, xmllint
ви можете нерестувати підпроцес і використовувати його.xmllint --format <file>
гарненько друкує свій вхідний XML на стандартний вихід.
Зауважте, що цей метод використовує програму, зовнішню до python, що робить його таким собі хаком.
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))
Я намагався редагувати відповідь "Аде" вище, але переповнення стека не дозволило мені редагувати після того, як я спочатку надав відгуки анонімно. Це менш глючна версія функції для гарного друку 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 += ' '
Якщо ви використовуєте реалізацію DOM, у кожного є своя вбудована форма друку:
# 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)
Якщо ви використовуєте щось інше без власного симпатичного принтера - або ті гарні принтери не зовсім роблять так, як вам хочеться - вам, мабуть, доведеться написати або підкласирувати власний серіалізатор.
У мене були деякі проблеми з гарненьким друком мінідома. Я б отримував UnicodeError кожного разу, коли я намагався красиво роздрукувати документ із символами, що не відповідають заданому кодуванню, наприклад, якщо у мене був β у документі, і я намагався doc.toprettyxml(encoding='latin-1')
. Ось мій спосіб вирішення цього питання:
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)
Він не додаватиме пробіли чи нові рядки всередині текстових вузлів, якщо ви не запитаєте про це за допомогою:
indent(mystring, indent_text = True)
Ви можете вказати, якою має бути одиниця відступу та якою має виглядати нова лінія.
pretty_xml_string = indent(
ugly_xml_string,
indentation = ' ',
newline = '\r\n'
)
Документ знаходиться на домашній сторінці http://www.yattag.org .
Я написав рішення, щоб пройти через існуюче ElementTree і використовувати текст / хвіст, щоб відступити його, як зазвичай очікує.
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 для python виглядає досить добре для цього завдання. (Відповідне ім’я теж.)
Альтернативою є використання pyXML , який має функцію PrettyPrint .
HTTPError: 404 Client Error: Not Found for url: https://pypi.org/simple/xmlpp/
Подумайте, що проект зараз на горищі, сором.
Ось рішення Python3, яке позбавляється від некрасивого питання про новий рядок (тонни пробілів), і воно використовує лише стандартні бібліотеки на відміну від більшості інших реалізацій.
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)
Я знайшов , як виправити загальну проблему перекладу рядка тут .
Ви можете використовувати популярну зовнішню бібліотеку xmltodict , з unparse
і pretty=True
ви отримаєте найкращий результат:
xmltodict.unparse(
xmltodict.parse(my_xml), full_document=False, pretty=True)
full_document=False
проти <?xml version="1.0" encoding="UTF-8"?>
вгорі.
Погляньте на модуль vkbeautify .
Це версія python мого дуже популярного плагіну javascript / nodejs з тим самим іменем. Це може досить друкувати / мінімізувати XML, JSON і CSS текст. Введення та вихід може бути рядок / файл у будь-яких комбінаціях. Він дуже компактний і не має ніякої залежності.
Приклади :
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')
Альтернативою, якщо вам не потрібно повторно розбирати, є бібліотека xmlpp.py з get_pprint()
функцією. Це працювало добре і плавно для моїх випадків використання, не потребуючи повторного розбору на lxml об’єкт ElementTree.
Ви можете спробувати цю варіацію ...
Встановіть BeautifulSoup
і резервні lxml
(парсер) бібліотеки:
user$ pip3 install lxml bs4
Обробіть свій XML-документ:
from bs4 import BeautifulSoup
with open('/path/to/file.xml', 'r') as doc:
for line in doc:
print(BeautifulSoup(line, 'lxml-xml').prettify())
'lxml'
використовує HTML- аналізатор lxml - дивіться документи BS4 . Вам потрібен 'xml'
або 'lxml-xml'
для аналізатора XML
lxml’s XML parser BeautifulSoup(markup, "lxml-xml") BeautifulSoup(markup, "xml")
lxml-xml
), і тоді вони того ж дня перейшли до її заклику. Я подав офіційну скаргу до S / O, але вони відмовилися від розслідування. У всякому разі, я з тих пір "знеструмив" свою відповідь, яка зараз знову є правильною (і вказує, lxml-xml
як це було раніше). Дякую.
Я мав цю проблему і вирішив її так:
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)
У моєму коді цей метод називається так:
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!")
Це працює лише тому, що etree за замовчуванням використовує two spaces
відступ, що я не вважаю дуже підкреслюючи відступ і тому не дуже. Я не міг вказати жодних параметрів для etree або параметрів жодної функції для зміни стандартного відступу etree. Мені подобається, як легко використовувати etree, але це мене справді дратувало.
Для перетворення всього XML-документа в гарний XML-документ
(наприклад: якщо припустити, що ви вилучили [unzipped] файл LibreOffice Writer .odt або .ods, і ви хочете перетворити потворний файл "content.xml" в гарний для автоматичне керування версіями git та git difftool
ing .odt / .ods файлів , таких як я тут реалізую )
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()
Список літератури:
- Завдяки відповіді Бен Ноланда на цій сторінці, яка пройшла до мене більшу частину шляху.
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=' ',))
Це добре працює для XML з китайською!
Якщо з якихось причин ви не можете отримати свої руки на будь-якому модулі Python, про який згадували інші користувачі, пропоную наступне рішення для 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)
Наскільки мені відомо, це рішення працюватиме на системах на базі Unix, на яких встановлений xmllint
пакет.
check_output
оскільки вам не потрібно робити перевірку помилок
Я вирішив це за допомогою рядків коду, відкривши файл, переглянувши його та додавши відступи, а потім знову збережи його. Я працював з невеликими xml-файлами, і не хотів додавати залежності або більше бібліотек, які потрібно встановити для користувача. У будь-якому випадку, ось що я закінчив:
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()
Це працює для мене, можливо, хтось буде цим користуватися :)