Письмо & ldquo; довольно напечатано & rdquo; с отступом xml в xml-файл приводит к неправильным уровням отступов [duplicate]

Третье решение, о котором я почти никогда не упоминал, имеет специфику MySQL и выглядит так:

SELECT id, MAX(rev) AS rev
 , 0+SUBSTRING_INDEX(GROUP_CONCAT(numeric_content ORDER BY rev DESC), ',', 1) AS numeric_content
FROM t1
GROUP BY id

Да, это выглядит ужасно (преобразование в строку и обратно и т. д.), но по моему опыту это обычно быстрее, чем другие решения. Возможно, это только для моих случаев использования, но я использовал его на таблицах с миллионами записей и множеством уникальных идентификаторов. Возможно, это связано с тем, что MySQL очень плохо оптимизирует другие решения (по крайней мере, в 5,0 дней, когда я придумал это решение).

Важно то, что GROUP_CONCAT имеет максимальную длину для строки, которую она может построить. Вероятно, вы захотите поднять этот предел, установив переменную group_concat_max_len. И имейте в виду, что это будет предел для масштабирования, если у вас есть большое количество строк.

В любом случае вышеупомянутое не работает напрямую, если ваше поле содержимого уже является текстом. В этом случае вы, вероятно, захотите использовать другой разделитель, например, \ 0. Вы также быстрее столкнетесь с пределом group_concat_max_len.

341
задан Apoorv Ingle 4 July 2015 в 14:23
поделиться

18 ответов

import xml.dom.minidom

xml = xml.dom.minidom.parse(xml_fname) # or xml.dom.minidom.parseString(xml_string)
pretty_xml_as_string = xml.toprettyxml()
311
ответ дан Ben Noland 1 September 2018 в 00:37
поделиться

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

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

8
ответ дан bobince 1 September 2018 в 00:37
поделиться

BeautifulSoup имеет простую в использовании функцию prettify().

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

from bs4 import BeautifulSoup

bs = BeautifulSoup(open(xml_file), 'xml')
print bs.prettify()
10
ответ дан ChaimG 1 September 2018 в 00:37
поделиться

Символьная печать XML для python выглядит довольно хорошо для этой задачи. (Соответственно названо тоже.)

Альтернативой является использование pyXML , который имеет функцию PrettyPrint .

3
ответ дан Daniel Lew 1 September 2018 в 00:37
поделиться

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

1
ответ дан gaborous 1 September 2018 в 00:37
поделиться

У меня были некоторые проблемы с красивой печатью миниода. Я бы получил 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')
6
ответ дан giltay 1 September 2018 в 00:37
поделиться

Другим решением является заимствование этой функции 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)
87
ответ дан Jimmy.Rustle 1 September 2018 в 00:37
поделиться
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 .

5
ответ дан John Smith Optional 1 September 2018 в 00:37
поделиться

lxml является последним, обновляется и включает в себя довольно печатную функцию

import lxml.etree as etree

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

Проверьте учебник lxml: http://lxml.de/tutorial.html

135
ответ дан Mad Physicist 1 September 2018 в 00:37
поделиться

Я написал решение, чтобы пройти через существующий 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
2
ответ дан nacitar sevaht 1 September 2018 в 00:37
поделиться

Вот мое решение (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>

Отказ от ответственности: Вероятно, существуют некоторые ограничения.

46
ответ дан Nick Bolton 1 September 2018 в 00:37
поделиться

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

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

-1
ответ дан Petter TB 1 September 2018 в 00:37
поделиться

Я попытался отредактировать ответ «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 += '  '
9
ответ дан Rónán Daly 1 September 2018 в 00:37
поделиться

Как отмечали другие, 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')
18
ответ дан roskakori 1 September 2018 в 00:37
поделиться

Если у вас есть 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
ответ дан Russell Silva 1 September 2018 в 00:37
поделиться

Взгляните на модуль 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') 
2
ответ дан vadimk 1 September 2018 в 00:37
поделиться

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

1
ответ дан Vitaly Zdanevich 1 September 2018 в 00:37
поделиться

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

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!")

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

0
ответ дан Zelphir 1 September 2018 в 00:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: