用Python打印XML的最佳方法(或各种方法)是什么?


当前回答

下面是一个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)

我找到了如何修复常见的换行符问题在这里。

其他回答

我看不懂迷你dom的漂亮印花。每当我尝试用给定编码之外的字符漂亮地打印文档时,我会得到一个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')

你可以试试这种变化……

安装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())  

你有几个选择。

xml etree ElementTree。缩进()

包括电池,使用简单,输出漂亮。

但需要Python 3.9+

import xml.etree.ElementTree as ET

element = ET.XML("<html><body>text</body></html>")
ET.indent(element)
print(ET.tostring(element, encoding='unicode'))

BeautifulSoup.prettify ()

BeautifulSoup可能是Python < 3.9最简单的解决方案。

from bs4 import BeautifulSoup

bs = BeautifulSoup(open(xml_file), 'xml')
pretty_xml = bs.prettify()
print(pretty_xml)

输出:

<?XML版本="1.0"编码="utf-8"?> <问题> <问题> <标识> 1 < / id > <标题> 添加Visual Studio 2005和2008解决方案文件 < /名称> > < /问题 > < /问题

这是我要回答的。默认实参按原样工作。但是文本内容在单独的行上展开,就好像它们是嵌套的元素一样。

lxml.etree.parse()

更漂亮的输出,但是带有参数。

from lxml import etree

x = etree.parse(FILE_NAME)
pretty_xml = etree.tostring(x, pretty_print=True, encoding=str)

生产:

<问题> <问题> <标识> 1 > < / id <title>添加Visual Studio 2005和2008解决方案文件 <details>我们需要Visual Studio 2005/2008的Windows项目文件 > < /问题 > < /问题

这对我来说没什么问题。


xml dom minidom parse()。

没有外部依赖,只有后处理。

import xml.dom.minidom as md

dom = md.parse(FILE_NAME)     
# To parse string instead use: dom = md.parseString(xml_string)
pretty_xml = dom.toprettyxml()
# remove the weird newline issue:
pretty_xml = os.linesep.join([s for s in pretty_xml.splitlines()
                              if s.strip()])

输出与上面相同,但是代码更多。

我试图编辑上面“ade”的回答,但在我最初匿名提供反馈后,Stack Overflow不让我编辑。这是一个bug较少的函数版本,用于漂亮地打印一个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 += '  '

正如其他人指出的那样,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')