Python中漂亮地打印XML

531

在Python中,美化XML的最佳方法是什么(或者有哪些方法)?

27个回答

8

我在使用minidom的pretty print时遇到了一些问题。当我尝试对一个包含给定编码之外字符(例如β)的文档进行pretty-print时,会出现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')

6

我写了一个解决方案,可以遍历现有的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

6
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首页找到。


5
以下是一份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)

我在这里找到了如何解决换行问题的方法。


4
你可以使用流行的外部库xmltodict,使用unparsepretty=True,您将获得最佳结果:
xmltodict.unparse(
    xmltodict.parse(my_xml), full_document=False, pretty=True)

在顶部使用 <?xml version="1.0" encoding="UTF-8"?>,而不是 full_document=False

3

HTTPError: 404 客户端错误:未找到 URL:https://pypi.org/simple/xmlpp/。这个项目现在可能已经被遗弃了,真可惜。 - 8bitjunkie
过时的答案,链接失效。 PyXML多年前已被放弃。 - mzjn

3
我在查找“如何漂亮地打印HTML”时发现了这个问题。
使用本主题中的一些思路,我改编了XML解决方案以适用于XML或HTML:
from xml.dom.minidom import parseString as string_to_dom

def prettify(string, html=True):
    dom = string_to_dom(string)
    ugly = dom.toprettyxml(indent="  ")
    split = list(filter(lambda x: len(x.strip()), ugly.split('\n')))
    if html:
        split = split[1:]
    pretty = '\n'.join(split)
    return pretty

def pretty_print(html):
    print(prettify(html))

When used this is what it looks like:

html = """\
<div class="foo" id="bar"><p>'IDK!'</p><br/><div class='baz'><div>
<span>Hi</span></div></div><p id='blarg'>Try for 2</p>
<div class='baz'>Oh No!</div></div>
"""

pretty_print(html)

返回结果如下:

<div class="foo" id="bar">
  <p>'IDK!'</p>
  <br/>
  <div class="baz">
    <div>
      <span>Hi</span>
    </div>
  </div>
  <p id="blarg">Try for 2</p>
  <div class="baz">Oh No!</div>
</div>

适用于Python 3.8,不支持其他答案中使用的indent - undefined

2

请看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') 

这个特定的库处理了丑陋文本节点问题。 - Cameron Lowell Palmer

2
您可以尝试这个变体...
安装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())  

1
这条评论一直被删除。我再次提交了正式投诉(除了4个flag之外),指控StackOverflow的帖子篡改,并且我将不会停止,直到安全团队进行法医调查(访问日志和版本历史记录)。上面的时间戳是错误的(已经过去几年),内容也可能是错的。 - NYCeyes
1
这对我来说很好用,不确定为什么文档会被踩。lxml 的 XML 解析器 BeautifulSoup(markup, "lxml-xml")BeautifulSoup(markup, "xml") - Umar.H
1
@Datanovice 很高兴它对你有帮助。:) 至于那个怀疑的踩,有人篡改了我的原始答案(最初正确指定为lxml-xml),然后在同一天踩了它。我向S/O提交了正式投诉,但他们拒绝调查。不管怎样,我现在已经“去篡改”了我的答案,现在又是正确的了(并像最初一样指定了lxml-xml)。谢谢。 - NYCeyes

1
我发现了一种快速简便的方式来美化和打印XML文件:
import xml.etree.ElementTree as ET

xmlTree = ET.parse('your XML file')
xmlRoot = xmlTree.getroot()
xmlDoc =  ET.tostring(xmlRoot, encoding="unicode")

print(xmlDoc)

输出:
<root>
  <child>
    <subchild>.....</subchild>
  </child>
  <child>
    <subchild>.....</subchild>
  </child>
  ...
  ...
  ...
  <child>
    <subchild>.....</subchild>
  </child>
</root>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接