PythonでXMLをきれいに印刷するための最良の方法(またはさまざまな方法)は何ですか?
27 に答える
import xml.dom.minidom
dom = xml.dom.minidom.parse(xml_fname) # or xml.dom.minidom.parseString(xml_string)
pretty_xml_as_string = dom.toprettyxml()
lxml は最近更新され、きれいな印刷機能が含まれています
import lxml.etree as etree
x = etree.parse("filename")
print etree.tostring(x, pretty_print=True)
lxml チュートリアルをチェックしてください: http://lxml.de/tutorial.html
もう 1 つの解決策は、2.5 以降 Python に組み込まれている ElementTree ライブラリで使用するために、このindent
関数を借用することです。これは次のようになります。
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)
醜いテキストノードの問題を回避するための私の(ハックな?)解決策は次のとおりです。
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>
免責事項:おそらくいくつかの制限があります。
他の人が指摘したように、lxml にはかなりのプリンターが組み込まれています。
ただし、デフォルトでは CDATA セクションが通常のテキストに変更されるため、厄介な結果になる可能性があることに注意してください。
入力ファイルを保持し、インデントのみを変更する Python 関数を次に示します ( に注意してstrip_cdata=False
ください)。さらに、出力がデフォルトの ASCII ではなく UTF-8 をエンコーディングとして使用するようにします ( に注意して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')
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/issue14465およびhttps://github.com/python/cpython/pull/15200を確認してください。
持っている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))
上記の「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 += ' '
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)
独自のプリティ プリンターを使用せずに他のものを使用している場合、またはそれらのプリティ プリンターが思いどおりに機能しない場合は、おそらく独自のシリアライザーを作成またはサブクラス化する必要があります。
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ホームページにあります。
私は、既存の 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
これは、醜い改行の問題 (大量の空白) を取り除き、他のほとんどの実装とは異なり、標準ライブラリのみを使用する 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)
ここで一般的な改行の問題を修正する方法を見つけました。
Python 用の XML プリティ プリントは、このタスクに適しているように見えます。(名前も適当に。)
別の方法は、PrettyPrint関数を持つpyXMLを使用することです。
一般的な外部ライブラリxmltodictを使用するunparse
とpretty=True
、最良の結果が得られます。
xmltodict.unparse(
xmltodict.parse(my_xml), full_document=False, pretty=True)
full_document=False
反対<?xml version="1.0" encoding="UTF-8"?>
する。
私はこれをいくつかのコード行で解決し、ファイルを開き、それを調べてインデントを追加し、再度保存しました。私は小さな 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()
それは私にとってはうまくいきます、おそらく誰かがそれを使用するでしょう:)