อะไรคือวิธีที่ดีที่สุด (หรือหลายวิธี) ในการพิมพ์ XML สวย ๆ ใน Python
อะไรคือวิธีที่ดีที่สุด (หรือหลายวิธี) ในการพิมพ์ XML สวย ๆ ใน Python
คำตอบ:
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
ห่าง ภายใต้ OS / 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');
นี่เป็นวิธีแก้ปัญหาของฉัน (hacky?) เพื่อแก้ไขปัญหาโหนดข้อความที่น่าเกลียด
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()
วิธีการใช้งานที่ง่าย
มันเยื้องหนึ่งช่องว่างต่อระดับการเยื้อง มันทำงานได้ดีกว่า pretty_print ของ 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
คุณสามารถวางไข่ subprocess และใช้มัน xmllint --format <file>
พริตตี้พิมพ์ XML ของอินพุตไปยังเอาต์พุตมาตรฐาน
โปรดทราบว่าวิธีนี้ใช้โปรแกรมภายนอกกับไพ ธ อนซึ่งทำให้เป็นแฮ็ค
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))
ฉันพยายามแก้ไขคำตอบ "ade" ด้านบน แต่ Stack Overflow จะไม่ให้ฉันแก้ไขหลังจากที่ฉันได้รับคำติชมโดยไม่ระบุชื่อ นี่เป็นฟังก์ชันรุ่น buggy ที่น้อยกว่าในการพิมพ์ 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)
หากคุณกำลังใช้งานอย่างอื่นโดยไม่มีเครื่องพิมพ์สวยของตัวเองหรือเครื่องพิมพ์สวย ๆ นั้นไม่ได้ทำอย่างที่คุณต้องการคุณอาจต้องเขียนหรือซับคลาสซีเรียลไลเซอร์ของคุณเอง
ฉันมีปัญหาบางอย่างกับงานพิมพ์ที่สวยงามของ minidom ฉันได้รับ 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 สวย ๆ สำหรับงูหลามดูดีสำหรับงานนี้ (ชื่อที่เหมาะสมเช่นกัน)
ทางเลือกคือการใช้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
มันเป็นเวอร์ชันหลามของปลั๊กอิน 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')
อีกทางเลือกหนึ่งถ้าคุณไม่ต้องการ reparse มีไลบรารี xmlpp.pyพร้อมget_pprint()
ฟังก์ชัน มันใช้งานได้ดีและราบรื่นสำหรับกรณีการใช้งานของฉันโดยไม่ต้องแยกชิ้นส่วนวัตถุ lxml ElementTree
คุณสามารถลองรูปแบบนี้ ...
ติดตั้งBeautifulSoup
และlxml
ไลบรารีbackend (parser):
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'
ใช้ lxml ของHTML parser - ดู BS4 เอกสาร คุณต้องการ'xml'
หรือ'lxml-xml'
สำหรับตัวแยกวิเคราะห์ XML
lxml’s XML parser BeautifulSoup(markup, "lxml-xml") BeautifulSoup(markup, "xml")
lxml-xml
) จากนั้นพวกเขาก็ลงคะแนนในวันเดียวกันนั้น ฉันส่งการร้องเรียนอย่างเป็นทางการไปยัง S / O แต่พวกเขาปฏิเสธที่จะตรวจสอบ อย่างไรก็ตามฉันมีตั้งแต่ "de-tampered" คำตอบของฉันซึ่งตอนนี้ถูกต้องอีกครั้ง (และระบุ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
การรับไฟล์. 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()
ข้อมูลอ้างอิง:
- ขอบคุณคำตอบของ Ben Noland ในหน้านี้ซึ่งทำให้ฉันได้รับประโยชน์มากที่สุด
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()
มันใช้งานได้สำหรับฉันบางทีอาจมีบางคนใช้มัน :)