使用 Python 漂亮地打印 XML

2024-12-02 08:41:00
admin
原创
238
摘要:问题描述:在 Python 中漂亮地打印 XML 的最佳方法是什么(或有多种方法)?解决方案 1:import xml.dom.minidom dom = xml.dom.minidom.parse(xml_fname) # or xml.dom.minidom.parseString(xml_string...

问题描述:

在 Python 中漂亮地打印 XML 的最佳方法是什么(或有多种方法)?


解决方案 1:

import xml.dom.minidom

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

解决方案 2:

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

import lxml.etree as etree

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

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

解决方案 3:

另一个解决方案是借用此indent函数,用于 Python 2.5 版以来内置的 ElementTree 库。如下所示:

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)

解决方案 4:

您有几种选择。

如果你使用的是 Python 3.9+,最简单的选择是:

xml.etree.ElementTree.缩进()

包含电池并且输出不错。

示例代码:

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 version="1.0" encoding="utf-8"?>
<issues>
 <issue>
  <id>
   1
  </id>
  <title>
   Add Visual Studio 2005 and 2008 solution files
  </title>
 </issue>
</issues>

这是我的答案。默认参数按原样工作。但文本内容分散在单独的行上,就像它们是嵌套元素一样。

lxml.etree.parse()

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

from lxml import etree

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

生成:

  <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.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()])

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

解决方案 5:

这是我解决丑陋的文本节点问题的(黑客?)解决方案。

uglyXml = doc.toprettyxml(indent='  ')

text_re = re.compile('>
s+([^<>s].*?)
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>

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

解决方案 6:

从 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'))

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

解决方案 7:

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

解决方案 8:

如果有的话,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))

解决方案 9:

我尝试编辑上面的“ade”的答案,但在我最初匿名提供反馈后,Stack Overflow 不允许我编辑。这是用于漂亮打印 ElementTree 的函数的错误较少的版本。

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 += '  '

解决方案 10:

如果您使用 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)

如果您正在使用没有自己的漂亮打印机的其他东西 - 或者那些漂亮的打印机不能完全按照您想要的方式执行 - 您可能必须编写或子类化您自己的序列化器。

解决方案 11:

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

解决方案 12:

from yattag import indent

pretty_string = indent(ugly_string)

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

indent(mystring, indent_text = True)

您可以指定缩进单位以及换行符的样子。

pretty_xml_string = indent(
    ugly_xml_string,
    indentation = '    ',
    newline = '
'
)

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

解决方案 13:

我编写了一个解决方案来遍历现有的 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 = '
' + 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

解决方案 14:

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

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

解决方案 15:

您可以使用流行的外部库xmltodict,unparsepretty=True将获得最佳结果:

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

full_document=False反对<?xml version="1.0" encoding="UTF-8"?>在顶部。

解决方案 16:

Python 的 XML 漂亮打印看起来非常适合这项任务。(名字也很恰当。)

另一种方法是使用pyXML,它具有PrettyPrint 功能。

解决方案 17:

我在寻找“如何漂亮地打印 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('
')))
    if html:
        split = split[1:]
    pretty = '
'.join(split)
    return pretty

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

使用时它看起来像这样:

html = """\n<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>

解决方案 18:

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

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

解决方案 19:

看一下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') 

解决方案 20:

如果您不想重新解析,可以使用带有该函数的xmlpp.py 库get_pprint()作为替代。它在我的用例中运行良好且流畅,无需重新解析为 lxml ElementTree 对象。

解决方案 21:

我找到了一种快速简便的方法来格式化和打印 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>

解决方案 22:

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

def write_xml_file (self, file, xml_root_element, xml_declaration=False, pretty_print=False, encoding='unicode', indent='    '):
    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)

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

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='    ')

except IOError:
    print("Error while writing in log file!")

这之所以有效,是因为 etree 默认使用two spaces缩进,而我发现缩进并没有特别强调缩进,因此不太美观。我找不到任何 etree 设置或任何函数参数来更改标准 etree 缩进。我喜欢 etree 的使用简便性,但这确实让我很恼火。

解决方案 23:

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运行良好!

解决方案 24:

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

解决方案 25:

将整个 xml 文档转换为漂亮的 xml 文档

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

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 在此页面上的回答,它帮助我解决了大部分问题。

解决方案 26:

使用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>

解决方案 27:

使用内置的 xml 库将给定的 XML 文件漂亮地打印到标准输出:

$ echo '<foo><bar>baz</bar><beer /><bank><account>000123</account></bank></foo>' > filename.xml
$ python -c 'import sys, xml.dom.minidom as xml; print(xml.parse(sys.argv[1]).toprettyxml(encoding="utf-8"))' filename.xml
<?xml version="1.0" encoding="utf-8"?>
<foo>
    <bar>baz</bar>
    <beer/>
    <bank>
        <account>000123</account>
    </bank>
</foo>

与 Python 2.7.18 配合良好。

解决方案 28:

我用几行代码解决了这个问题,打开文件,浏览并添加缩进,然后再次保存。我处理的是小型 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 += '
' + 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()

它对我有用,也许有人会用到它:)

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用