在Python中打印XML

时间:2009-04-15 00:05:41

标签: python xml pretty-print

在Python中打印xml的最佳方式(甚至是各种方法)是什么?

27 个答案:

答案 0 :(得分:343)

import xml.dom.minidom

dom = xml.dom.minidom.parse(xml_fname) # or xml.dom.minidom.parseString(xml_string)
pretty_xml_as_string = dom.toprettyxml()

答案 1 :(得分:144)

lxml是最新的,已更新,并包含一个漂亮的打印功能

import lxml.etree as etree

x = etree.parse("filename")
print etree.tostring(x, pretty_print=True)

查看lxml教程: http://lxml.de/tutorial.html

答案 2 :(得分:97)

另一个解决方案是借用this indent function,以便与2.5之后内置于Python的ElementTree库一起使用。 这就是看起来的样子:

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)

答案 3 :(得分:46)

这是解决丑陋的文本节点问题的(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>

免责声明:可能存在一些限制。

答案 4 :(得分:21)

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

答案 5 :(得分:13)

BeautifulSoup有一个易于使用的prettify()方法。

每个缩进级别缩进一个空格。它的效果比lxml的pretty_print好得多,而且简短而且甜美。

from bs4 import BeautifulSoup

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

答案 6 :(得分:11)

我尝试编辑上面的“ade”答案,但在我最初匿名提供反馈后,Stack Overflow不会让我编辑。这是一个不那么错误的版本的功能来漂亮地打印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 += '  '

答案 7 :(得分:10)

如果你有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))

答案 8 :(得分:8)

如果你正在使用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)

如果您在没有自己的漂亮打印机的情况下使用其他东西 - 或者那些漂亮的打印机没有按照您想要的方式进行操作 - 您可能必须编写或子类化您自己的序列化程序。

答案 9 :(得分:6)

我在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')

答案 10 :(得分:5)

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主页。

答案 11 :(得分:4)

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

我发现了如何解决常见的换行问题here

答案 12 :(得分:3)

我编写了一个解决方案来遍历现有的ElementTree,并使用text / tail缩进它,就像人们通常期望的那样。

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

答案 13 :(得分:3)

从Python 3.9(到2020年8月12日仍是候选版本)开始,有一个新的xml.etree.ElementTree.indent()函数用于漂亮地打印XML树。

样品用量:

import xml.etree.ElementTree as ET

element = ET.XML("<html><body>text</body></html>")
ET.indent(element)

好处是它不需要任何其他库。有关更多信息,请检查https://bugs.python.org/issue14465https://github.com/python/cpython/pull/15200

答案 14 :(得分:3)

XML pretty print for python看起来非常适合这项任务。 (也恰当地命名。)

另一种方法是使用pyXML,其PrettyPrint function

答案 15 :(得分:2)

您可以使用热门外部资源库xmltodictunparsepretty=True,您将获得最佳效果:

xmltodict.unparse(
    xmltodict.parse(my_xml), full_document=False, pretty=True)

full_document=False顶部的<?xml version="1.0" encoding="UTF-8"?>

答案 16 :(得分:2)

查看vkbeautify模块。

这是我非常流行的javascript / nodejs插件的python版本,名称相同。它可以漂亮地打印/缩小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') 

答案 17 :(得分:1)

如果您不想重新分析,则可以使用xmlpp.py library get_pprint()函数。对于我的用例,它工作得很顺利,而不必重新解析为lxml的ElementTree对象。

答案 18 :(得分:0)

用于将整个xml文档转换为漂亮的xml文档
(例如:假设您已提取[解压缩] LibreOffice Writer .odt或.ods文件,并且想要将丑陋的“ content.xml”文件转换为漂亮的文件,以进行自动git版本控制 git difftool的.odt / .ods文件 ,例如我正在实现here

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's answer on this page,这使我几乎步入正轨。

答案 19 :(得分:0)

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来说效果很好!

答案 20 :(得分:0)

我遇到了这个问题并解决了这个问题:

<p></p>

在我的代码中,这个方法被调用如下:

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)

这只是因为etree默认使用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缩进的etree或参数设置任何设置。我喜欢使用etree是多么容易,但这真让我讨厌。

答案 21 :(得分:0)

如果由于某种原因您无法使用其他用户提到的任何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)

据我所知,该解决方案将在安装了xmllint软件包的基于Unix的系统上运行。

答案 22 :(得分:0)

我在寻找“如何漂亮地打印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))

使用时,外观如下:

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>

答案 23 :(得分:0)

使用etree.indentetree.tostring

import lxml.etree as etree

root = etree.fromstring('<html><head></head><body><h1>Welcome</h1></body></html>')
etree.indent(root, space="  ")
xml_string = etree.tostring(root, pretty_print=True).decode()
print(xml_string)

输出

<html>
  <head/>
  <body>
    <h1>Welcome</h1>
  </body>
</html>

删除名称空间和前缀

import lxml.etree as etree


def dump_xml(element):
    for item in element.getiterator():
        item.tag = etree.QName(item).localname

    etree.cleanup_namespaces(element)
    etree.indent(element, space="  ")
    result = etree.tostring(element, pretty_print=True).decode()
    return result


root = etree.fromstring('<cs:document xmlns:cs="http://blabla.com"><name>hello world</name></cs:document>')
xml_string = dump_xml(root)
print(xml_string)

输出

<document>
  <name>hello world</name>
</document>

答案 24 :(得分:0)

我找到了一种很好地打印 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>

答案 25 :(得分:-1)

您可以尝试这种变化...

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

答案 26 :(得分:-1)

我用一些代码解决了这个问题,打开文件,通过它并添加缩进,然后再次保存。我正在处理小的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()

它适用于我,也许有人会使用它:)