Pretty printing XML in Python
在Python中漂亮地打印XML的最佳方法(甚至是各种方法)是什么?
1 2 3 4 | 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是最新的、更新的,并且包含一个漂亮的打印函数
1 2 3 4 | import lxml.etree as etree x = etree.parse("filename") print etree.tostring(x, pretty_print=True) |
查看lxml教程:http://lxml.de/tutorial.html
另一种解决方案是借用这个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | from xml.etree import ElementTree def indent(elem, level=0): i =" " + level*" " j =" " + (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) |
这是我的(哈奇?)解决了难看的文本节点问题。
1 2 3 4 5 6 7 8 | uglyXml = doc.toprettyxml(indent=' ') text_re = re.compile('> \s+([^<>\s].*?) \s+</', re.DOTALL) prettyXml = text_re.sub('>\g<1></', uglyXml) print prettyXml |
上述代码将产生:
1 2 3 4 5 6 7 8 | <?xml version="1.0" ?> <issues> <issue> <id>1</id> Add Visual Studio 2005 and 2008 solution files <details>We need Visual Studio 2005/2008 project files for Windows.</details> </issue> </issues> |
而不是这个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?xml version="1.0" ?> <issues> <issue> <id> 1 </id> Add Visual Studio 2005 and 2008 solution files <details> We need Visual Studio 2005/2008 project files for Windows. </details> </issue> </issues> |
免责声明:可能有一些限制。
正如其他人指出的,LXML内置了一个漂亮的打印机。
但是要注意,默认情况下,它会将CDATA部分更改为普通文本,这可能会产生令人讨厌的结果。
这里有一个python函数,它保存输入文件,只更改缩进(注意
1 2 3 4 5 6 7 | 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') |
示例用法:
1 | prettyPrintXml('some_folder/some_file.xml') |
美汤有一个易于使用的方法。
每个缩进级别缩进一个空格。它比LXML的漂亮打印效果好得多,而且短而甜。
1 2 3 4 | from bs4 import BeautifulSoup bs = BeautifulSoup(open(xml_file), 'xml') print bs.prettify() |
我试图编辑上面的"ade"的答案,但在我最初匿名提供反馈后,堆栈溢出将不允许我编辑。这是一个不那么麻烦的版本,可以漂亮地打印元素树。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | def indent(elem, level=0, more_sibs=False): i =" " 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 += ' ' |
如果您有
注意,这个方法使用了一个Python外部的程序,这使得它有点像黑客。
1 2 3 4 5 6 7 8 9 10 | 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)) |
如果您使用的是DOM实现,则每个实现都有自己的漂亮打印形式内置:
1 2 3 4 5 6 7 8 9 10 11 12 | # 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) |
如果你用的是没有自己漂亮打印机的其他东西?-?或者那些漂亮的打印机不太符合你的要求?-?您可能需要编写自己的serialiser或将其子类化。
我对Minidom漂亮的印刷品有一些问题。每当我尝试用给定编码之外的字符打印文档时,我都会得到一个单代码错误,例如,如果文档中有一个β,并且我尝试了
1 2 3 4 5 | 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') |
1 2 3 | from yattag import indent pretty_string = indent(ugly_string) |
它不会在文本节点中添加空格或换行符,除非您使用以下命令进行请求:
1 | indent(mystring, indent_text = True) |
您可以指定缩进单位应该是什么,换行符应该是什么样子。
1 2 3 4 5 6 7 | pretty_xml_string = indent( ugly_xml_string, indentation = ' ', newline = ' ' ) |
该文件位于http://www.yattag.org主页上。
XML Pretty Print for Python看起来非常适合此任务。(名字也恰当。)
另一种选择是使用pyxml,它具有预打印功能。
我编写了一个解决方案来遍历现有的元素树,并使用文本/尾部按人们通常期望的方式缩进它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 = ' ' + indent * (level+1) # for child open if queue: element.tail = ' ' + indent * queue[0][0] # for sibling open else: element.tail = ' ' + indent * (level-1) # for parent close queue[0:0] = children # prepend so children come before siblings |
您可以使用流行的外部库xmltodict,使用
1 2 | xmltodict.unparse( xmltodict.parse(my_xml), full_document=False, pretty=True) |
在顶部,
看看VKbeautify模块。
这是我的一个非常流行的javascript/nodejs插件的python版本,同名。它可以很好地打印/缩小XML、JSON和CSS文本。输入和输出可以是任意组合的字符串/文件。它非常紧凑,没有任何依赖性。
实例:
1 2 3 4 5 6 | 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') |
另一种选择是,如果您不想重新分析,可以使用带有
用于将整个XML文档转换为漂亮的XML文档(例如:假设您提取了libreoffice writer.odt或.ods文件[解压],并且希望将丑陋的"content.xml"文件转换为一个漂亮的文件,用于自动Git版本控制和.odt/.ods文件的
1 2 3 4 5 6 7 8 9 10 11 12 | 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() |
参考文献:-多亏了本·诺兰在这一页上的回答,这让我大受欢迎。
我遇到了这个问题,就这样解决了:
1 2 3 4 | 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) |
在我的代码中,此方法的调用方式如下:
1 2 3 4 5 6 7 8 9 10 11 | 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在默认情况下使用
我用一些代码行来解决这个问题,打开文件,浏览它并添加缩进,然后再次保存它。我正在处理小的XML文件,不想添加依赖项,也不想为用户安装更多的库。不管怎样,我的结论是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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 += ' ' + indent*deepness simpleSplit = False deepness += -1 if(simpleSplit): new_xml += ' ' + indent*deepness if(start): deepness += 1 if(end): deepness += -1 f = open(file_name,'w') f.write(new_xml) f.close() |
它对我有用,也许有人会用到它。)