Довольно печатать XML в Python

Каков наилучший (или различные) способ печатать XML в Python?

Ответ 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: http://lxml.de/tutorial.html

Ответ 3

Другим решением является заимствовать эту функцию indent для использования с библиотекой ElementTree, встроенной в Python с 2,5. Вот как это будет выглядеть:

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)

Ответ 4

Здесь мое (хакерское?) решение, чтобы обойти проблему уродливого текста node.

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>

Отказ от ответственности: Есть, вероятно, некоторые ограничения.

Ответ 5

Как отмечали другие, 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')

Ответ 6

BeautifulSoup имеет простой в использовании prettify().

Он отступает один пробел на уровень отступа. Он работает намного лучше, чем lxml pretty_print, и он короткий и приятный.

from bs4 import BeautifulSoup

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

Ответ 7

Я попытался отредактировать ответ "ade" выше, но Qaru не разрешил мне редактировать после того, как я первоначально предоставил анонимную обратную связь. Это менее сложная версия функции для правильной печати 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 += '  '

Ответ 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

Если вы используете реализацию 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)

Если вы используете что-то еще без своего собственного принтера-принтера, или те симпатичные принтеры не делают этого так, как вы хотите, вам, вероятно, придется писать или подклассифицировать собственный сериализатор.

Ответ 10

У меня были некоторые проблемы с мини-принтом. Я бы получил 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')

Ответ 11

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.

Ответ 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 = '\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

Ответ 14

Вы можете использовать популярную внешнюю библиотеку 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"?> вверху.

Ответ 15

Взгляните на модуль vkbeautify.

Это версия python моего очень популярного плагина javascript/nodejs с тем же именем. Он может печатать/минимизировать 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') 

Ответ 16

Альтернативой, если вы не хотите переписывать, есть библиотека xmlpp.py с помощью функции get_pprint(). Он работал красиво и гладко для моих случаев использования, не переписывая объект lxml ElementTree.

Ответ 17

У меня была эта проблема и она была решена так:

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)

В моем коде этот метод называется следующим:

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 по умолчанию использует two spaces для отступа, и я не очень сильно подчеркиваю отступ и, следовательно, не очень. Я не мог указывать какие-либо настройки для etree или параметра для любой функции, чтобы изменить стандартный отступ epree. Мне нравится, как легко использовать etree, но это меня действительно раздражало.

Ответ 18

Для преобразования всего XML-документа в документ xml
(например: если вы извлекли [распаковали] файл LibtOffice.odt или.ods, и вы хотите преобразовать уродливый файл "content.xml" в красивую для автоматического управления версиями git difftool и git difftool ing.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()

Рекомендации:
- Спасибо Бен Ноланду ответить на эту страницу, которая доставила мне большую часть пути.

Ответ 19

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

Вы можете попробовать этот вариант...

Установите библиотеки 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())  

Ответ 21

Я решил это с некоторыми строками кода, открыв файл, перейдя через него и добавив отступ, а затем сохранил его снова. Я работал с небольшими файлами 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()

Это работает для меня, возможно, кто-то будет использовать его:)