在Python中打印XML

Hor*_*ude 401 python xml pretty-print

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

Ben*_*and 362

import xml.dom.minidom

dom = xml.dom.minidom.parse(xml_fname) # or xml.dom.minidom.parseString(xml_string)
pretty_xml_as_string = dom.toprettyxml()
Run Code Online (Sandbox Code Playgroud)

  • @icnivad:虽然重要的是要指出这个事实,但对我来说,如果空间对他们来说有些重要,那么有人会想要美化它的XML似乎很奇怪! (44认同)
  • 这会让你很漂亮xml,但请注意文本节点中出现的内容实际上与进入的内容不同 - 文本节点上有新的空格.如果你期望完全输入饲料的东西,这可能会给你带来麻烦. (32认同)
  • 不是将xml重新定义为从模块到输出对象的粉丝,但该方法无效.我很想找到一个更好的方法从核心etree到漂亮的打印.虽然lxml很酷,但有时候如果可以的话,我宁愿保持核心. (25认同)
  • 太好了!可以将其折叠为一个衬里:python -c'import sys; import xml.dom.minidom; s = sys.stdin.read(); print xml.dom.minidom.parseString(s).toprettyxml()' (18认同)
  • minidom被广泛淘汰为一个非常糟糕的xml实现.如果你允许自己添加外部依赖性,lxml是非常优越的. (10认同)
  • 到处都是大量疯狂的空白线条.此解决方案不起作用. (8认同)
  • 这是在我每次运行时插入额外的空格,在我看来这是破碎的.(Python 2.6和2.7) (6认同)
  • 链接到文档:https://docs.python.org/2/library/xml.dom.minidom.html#xml.dom.minidom.Node.toprettyxml (2认同)
  • 是的,这实际上是一个非常糟糕的解决方案。 (2认同)
  • 在2.6中,文本节点中有换行符和空格,但是2.7,文本节点看起来没有变化. (2认同)
  • 值得注意的是,这仍然是一些相当丑陋的XML:似乎没有一种可靠的方式来美化XML的方式不是那么丑陋,而我所说的是所有丑陋的丑陋行为。标签属性在同一行上,而不是在单独的行上。 (2认同)
  • xml.toprettyxml(indent =“”,newl =“”)`可以有4个缩进空间,而且到处都没有换行符。添加单行代码:`python -c'import sys,xml.dom.minidom as xmld; print(xmld.parse(sys.argv [1])。toprettyxml(indent =“”,newl =“”))'my_xml_file.xml` (2认同)
  • 要删除它生成的丑陋的空行,只需添加如下内容即可删除空行:`pretty_xml_as_string ='\ n'.join(list(filter(lambda x:len(x.strip()),pretty_xml_as_string.split(' \ n'))))` (2认同)

172*_*729 154

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

import lxml.etree as etree

x = etree.parse("filename")
print etree.tostring(x, pretty_print=True)
Run Code Online (Sandbox Code Playgroud)

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

  • 因为在Python 3中你通常想使用str(= Python 2中的unicode字符串),所以最好使用它:`print(etree.tostring(x,pretty_print = True,encoding ="unicode"))`.只需一行就可以写入输出文件,不需要中间变量:`etree.parse("filename").write("outputfile",encoding ="utf-8")` (13认同)
  • lxml漂亮的打印机不可靠,并且在[lxml FAQ](http://lxml.de/FAQ.html#why-doesn-t-the-pretty-print)中解释的很多情况下都无法正确打印XML. - 选项 - 格式化 - 我的XML输出).在几个不起作用的极端情况之后我退出使用lxml进行漂亮打印(即这不会修复:[Bug#910018](https://bugs.launchpad.net/lxml/+bug/910018)).所有这些问题都与使用包含应保留的空格的XML值有关. (11认同)
  • lxml的唯一缺点是对外部库的依赖.我认为在Windows下,库与模块打包在一起并不是那么糟糕.在linux下,他们是一个'aptitude install`.在OS/X下,我不确定. (10认同)
  • 在OS X上,您只需要一个正常运行的gcc和easy_install/pip. (4认同)
  • `etree.XMLParser(remove_blank_text=True)` 有时可以帮助进行正确的打印 (2认同)

ade*_*ade 105

另一个解决方案是借用这个indent函数,与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)
Run Code Online (Sandbox Code Playgroud)

  • 此链接http://effbot.org/zone/element-lib.htm#prettyprint具有正确的代码.这里的代码有些不对劲.需要编辑. (14认同)
  • 请注意,您仍然可以使用`tree.write([filename])`来写入文件(`tree`是ElementTree实例). (2认同)

Nic*_*ton 47

这是解决丑陋文本节点问题的(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
Run Code Online (Sandbox Code Playgroud)

上面的代码将产生:

<?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>
Run Code Online (Sandbox Code Playgroud)

而不是这个:

<?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>
Run Code Online (Sandbox Code Playgroud)

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

  • 在Python 2.7中不再需要这样做:xml.dom.minidom的toprettyxml()现在默认生成类似'<id> 1 </ id>'的输出,对于只有一个文本子节点的节点. (3认同)

ros*_*ori 22

正如其他人所指出的那样,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')
Run Code Online (Sandbox Code Playgroud)

用法示例:

prettyPrintXml('some_folder/some_file.xml')
Run Code Online (Sandbox Code Playgroud)

  • 现在有点晚了。但我认为 lxml 修复了 CDATA?CDATA 是我这边的 CDATA。 (2认同)

Cha*_*imG 17

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

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

from bs4 import BeautifulSoup

bs = BeautifulSoup(open(xml_file), 'xml')
print bs.prettify()
Run Code Online (Sandbox Code Playgroud)


o15*_*1s2 17

从 Python 3.9 开始,ElementTree 有一个indent()用于漂亮打印 XML 树的函数。

请参阅https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.indent

示例用法:

import xml.etree.ElementTree as ET

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

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


Jos*_*son 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 += '  '
Run Code Online (Sandbox Code Playgroud)


Rus*_*lva 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))
Run Code Online (Sandbox Code Playgroud)


bob*_*nce 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)
Run Code Online (Sandbox Code Playgroud)

如果你在没有自己的漂亮打印机的情况下使用别的东西 - 或者那些漂亮的打印机不能按照你想要的方式完成它 - 你可能必须编写或子类化你自己的序列化器.


gil*_*tay 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')
Run Code Online (Sandbox Code Playgroud)


Joh*_*nal 5

from yattag import indent

pretty_string = indent(ugly_string)
Run Code Online (Sandbox Code Playgroud)

它不会在文本节点中添加空格或换行符,除非您要求:

indent(mystring, indent_text = True)
Run Code Online (Sandbox Code Playgroud)

您可以指定缩进单元应该是什么以及换行应该是什么样的.

pretty_xml_string = indent(
    ugly_xml_string,
    indentation = '    ',
    newline = '\r\n'
)
Run Code Online (Sandbox Code Playgroud)

该文档位于http://www.yattag.org主页.


nac*_*aht 5

我编写了一个解决方案来遍历现有的 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
Run Code Online (Sandbox Code Playgroud)


Jos*_*eia 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)
Run Code Online (Sandbox Code Playgroud)

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